2017-10-12 3 views
0

이전 질문 중 하나 (dynamically create md-card from API response)에서 API의 응답에 따라 카드를 동적으로 만듭니다. 관찰 가능 변경시에도보기가 업데이트되지 않음

는 API 호출을 만드는 서비스입니다 :

@Injectable() 
export class WebSearchService { 

    private readonly _results$$ = new BehaviorSubject([]); 
    private readonly _isLoading$$ = new BehaviorSubject(false); 

    public readonly results$ = this._results$$.asObservable().shareReplay(); 
    public readonly isLoading$ = this._isLoading$$.asObservable(); 

    public term: string; 
    p: number; // page 

    public config = { 
    itemsPerPage: 10, 
    currentPage: this.p, 
    totalItems: 100 
    }; 

    constructor(private http: Http){ 
    } 

    search(term: string, page?: number){ 

    return this.http.get(`my/api/{term}`).do(response => { 
     this._isLoading$$.next(false); 
     this.config.totalItems = response.json().estimated_total; 
     this.config.currentPage = this.p; 
    }) 
     .map(response => response.json().results as WebResult[]).map(result => { 
     this._results$$.next(result); 
     this.term = term; 
     return result; 
     }) 
    .take(1); 
    } 

    updatePage(page: number){ 
    this.p = page; 
    return this.search(this.term, page); 
    } 

} 

서비스에서 결과를 사용하는 구성 요소 :

export class ResultsComponent implements OnInit { 
    private readonly _results$$ = new BehaviorSubject([]); 

    public readonly isLoading$ = this.webService.isLoading$; 
    public results$ = this.webService.results$; 
    p = 1; // 

    constructor(public webService: WebSearchService) { } 

    ngOnInit() { // 
    } 

    changePage(page: number){ 
    console.log('Page: ' + page); 
    this.results$ = this.webService.updatePage(page); 
    } 

및 템플릿 : 내가 가지고있는

<ng-template [ngIf]="isLoading$ | async" [ngIfElse]="results"> 
    is loading ... 
</ng-template> 

<ng-template #results> 
    <div class="container-fluid" *ngFor="let result of results | paginate: this.webService.config"> 
    <!-- cards get dynamically created here --> 
    </div> 
</ng-template> 
<pagination-controls *ngIf="(results$ | async)?.length>0" maxSize="6" 
        previousLabel="" 
        nextLabel="" 
        align="center" 
        (pageChange)="changePage($event)" 
        class="my-pagination" 
        screenReaderPaginationLabel="Pagination" 
        screenReaderPageLabel="page" 
        screenReaderCurrentLabel="You are on page" 
        autoHide="true" 
></pagination-controls> 

서비스에서 search 메서드를 호출하는 다른 구성 요소. 그러나 페이지 1을 제외한 모든 페이지에서 검색이 호출되는 경우보기가 업데이트되지 않습니다. 결과보기의 3 페이지로 이동 한 다음 다른 검색을 수행하면 results$ 관찰 가능이 업데이트되지만보기는 이전 검색 결과에 남아 있습니다. 새로운 결과를 얻으려면 수동으로 페이지 1로 변경해야합니다. 보기를 자동으로 새로 고치는 방법이 있습니까?

문제를 설명하기 위해 최선을 다했습니다. 프로젝트가 상당히 커서 plunkr을 만들 수는 없지만 더 많은 코드를 설명하고 제공하고자합니다.

도움을 주시면 감사하겠습니다.

+0

음, 솔직히 말해서 .. NgZone 또는 ChangeDetectorRef와 같은 복잡한 것을 고려하는 것부터 시작하지 않는 코드에는 많은 문제가 있습니다. 실제로 문제가 될 수 있기 전에 수정해야 할 사항이 많이 있습니다 ... 그러나 나는 그렇지 않습니다. 정말로 당신이하려는 것을 얻으십시오. 예를 들어, 왜 observables로 변환하는 BehaviorSubjects가 너무 많습니까? http.get() 매핑 된 결과를 반환하는 것으로 충분하지 않습니까? 어떤 종류의 캐싱을 구현하려고합니까? 그리고 힌트 : 즉각적인 문제는 ResultsComponent.changePage() 함수에 있습니다. –

+0

몇 가지 제안이나 개선점을 제공해 줄 수 있습니까? – bawse

+0

물론 할 수는 있지만 시작해야 할 것이 있습니다. 나는 당신이하려고하는 것을 보지 못한다. 그래서 그것에 대한 통찰력을주지 않는다면 나는 의미있는 것을 제안 할 수 없을 것이다. 당신은 ***에 대해 묘사하고 있습니다 *** *** 그리고 *** *** 당신이하고있는 것 - 구성 요소 A와 같은 구성 요소 A를 만들었습니다. 이 방법은 다른 방법이 아닙니다. 당신이 해결하려고하는 실제 업무를 이해하고 싶습니다. –

답변

1

관측 가능 기능의 success 또는 error 함수는 각도 영역을 거의 다 써 버렸습니다. 즉, 새 값을 내보낼 때 각도 변화 감지가 실행되지 않습니다. ChangeDetectorRef을 사용하면 해당 값이 업데이트 될 때 수동으로 변경 감지를 실행할 수 있습니다.

constructor(private cdr: ChangeDetectorRef) {} // inject in your constructor 

myObservable.subscribe(value => { 
    this.myValue = value; // update out of scope 
    this.cdr.detectChanges(); // run change detection manually 
}); 

당신은 또한 수동으로 results$ 관찰을 구독하고 인스턴스 변수에 새로운 값이 도착할 때마다 업데이트 할 수 있습니다. 인스턴스 변수는 ngFor 지시문에 사용됩니다. 난 당신의 코드와 관련이없는 모든 것을 제거하고 내가 무슨 뜻인지 보여주기 위해 간단한 예를 추가 :

클래스 :

export class ResultsComponent implements OnInit { 
    private results$ = this.webService.results$; 
    public results = []; 

    constructor(private webService: WebSearchService, private cdr: ChangeDetectorRef) { 
    this.results$.subscribe(result => { 
     this.results = result; 
     this.cdr.detectChanges(); 
    }); 
    } 
} 

그리고 템플릿 :

<div *ngFor="let result of results | paginate: this.webService.config"></div> 

<pagination-controls 
    *ngIf="results.length > 0" 
    maxSize="6" previousLabel="" 
    nextLabel="" 
    align="center" 
    (pageChange)="changePage($event)" 
    class="my-pagination" 
    screenReaderPaginationLabel="Pagination" 
    screenReaderPageLabel="page" 
    screenReaderCurrentLabel="You are on page" 
    autoHide="true"> 
</pagination-controls> 
+0

페이지 번호를 눌러서 첫 페이지에 머물러 있지 않으면보기가 새로 고침됩니다. 그러나 다른 페이지로 이동 한 다음 계속해서 검색어를 변경하면 문제가 발생합니다.'results $'는 여전히 변경 사항을 받지만 뷰에는 반영되지 않습니다. 나는 당신의 제안을 시도했으나 문제는 남아 있습니다. – bawse

+0

$ observable (비동기 파이프가 아닌) 결과를 수동으로 구독하고 결과 $가 업데이트를받을 때마다 업데이트되는 템플릿의 ngFor에 인스턴스 변수를 사용하려고 시도 했습니까? – David

+0

아니, 나는 그걸 시도하지 않았다. 위에서 작성한 코드를 사용하여 예제를 제공 할 수 있습니까? – bawse

관련 문제