为什么我需要使用默认的更改检测策略调用detectChanges()?

时间:2017-07-21 11:36:01

标签: angular typescript angular2-changedetection

我正在开发一个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中。

2 个答案:

答案 0 :(得分:7)

我已经解决了这个问题。

向此组件发送通知的另一个组件是在Angular区域外运行Observable.fromEvent(),因此更改检测不会自动响应这些事件。 This post on zonesthis StackOverflow post就该问题提出了解决方案!

答案 1 :(得分:0)

您可以将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时,都会在子组件中填充更改,子模板中的值将获得新值。