web-dev-qa-db-ja.com

デフォルトの変更検出戦略でdetectChanges()を呼び出す必要があるのはなぜですか?

私はAngular 4アプリで作業していますが、モデルが変更されたときにビューを更新するためにthis.changeDetectorRef.detectChanges();を呼び出さなければならないので問題があります。たとえば、ページネーション用のこのコードがあります:

_changePage(pageNumber) {
  this.currentPage = pageNumber;
  // why do I need to do this?
  this.changeDetectorRef.detectChanges();
}
_

コンポーネントの変更検出戦略を_ChangeDetectionStrategy.Default_に明示的に設定しましたが、これは効果がありません。ここでも、オブザーバブルをサブスクライブするときに発生します。

_showResults(preference) {
  this.apiService.get('dining_autocomplete/', `?search=${preference}`)
    .subscribe((results) => {
      this.searchResults = results;
      // why do I need to do this?
      this.changeDetectorRef.detectChanges();
  });
}
_

TypeScriptでconsole.log() _this.searchResults_を使用すると、期待どおりの結果が得られますが、HTMLで_{{ searchResults }}_を使用すると、おそらく他のイベントが発生するまで更新されません。別のダイジェストサイクルを経ます。

何が起こっているのでしょうか?

==編集============================================== ============

コンポーネントのコードは次のようになります。

_import {ChangeDetectorRef, Component, Input, OnChanges} from "@angular/core";

import * as _ from 'lodash';

@Component({
  selector: 'dining-search-results',
  templateUrl: './dining-search-results.template.html',
  styleUrls: ['./dining-search-results.style.scss'],

})
export class DiningSearchResultsComponent {
  @Input() searchResults: any[];
  @Input() hotTablesOnly: boolean = false;
  @Input() memberBenefitsOnly: boolean = false;

  numberOfTagsToDisplay: number = 3;
  resultsPerPage: number = 5;
  currentPage: number = 1;

  constructor(private changeDetectorRef: ChangeDetectorRef) {
  }

  get filteredResults() {
    return this.searchResults ?
      this.searchResults.filter((r) => !((this.hotTablesOnly && !r.has_hot_table)
        || (this.memberBenefitsOnly && !r.has_member_benefit))) : [];
  }

  get pagedResults() {
    return _.chain(this.filteredResults)
      .drop(this.resultsPerPage * (this.currentPage - 1))
      .take(this.resultsPerPage)
      .value();
  }

  get totalPages(): number {
    return Math.ceil(this.filteredResults.length / this.resultsPerPage);
  }

  getInitialTags(tagsArray: any[], count: number): any[] {
    return _.take(tagsArray, count);
  }

  changePage(pageNumber) {
    this.currentPage = pageNumber;
    // why do I need to do this?
    this.changeDetectorRef.detectChanges();
  }
}
_

changePage()が呼び出され、_this.currentPage_が更新されると、detectChanges()を呼び出さない限り、変更はHTMLに反映されません。

8
serlingpa

私は問題を解決しました。

このコンポーネントに通知を送信する別のコンポーネントは、Angularゾーンの外側でObservable.fromEvent()を実行していたため、これらのイベントに応じて変更検出は自動的に行われませんでした。 この投稿ゾーン および このStackOverflowの投稿 の問題については解決策がありました!

8
serlingpa

searchResultsを子コンポーネントに入力できます

@Input() searchResults;

その後、親テンプレートを介して渡します

// parent template
<app-child [searchResults]="searchResults"></app-child>

子テンプレートで使用できます

// child template 
<my-date-picker [ngModel]="searchResults"></my-date-picker>

その後、子コンポーネントのこのプロパティの変更を「聞く」ことができます

export class ChildComponent implements OnChanges {

  @Input() searchResults;

  constructor() { }

  ngOnChanges() {
    // some code
  }

searchResultsが変更されるたびに、子コンポーネントに変更が入力され、子テンプレートの値が新しい値を取得します。

0
onetwo12