【问题标题】:Why do I need to call detectChanges() with the default change detection strategy?为什么我需要使用默认更改检测策略调用 detectChanges()?
【发布时间】:2017-12-27 10:43:50
【问题描述】:

我正在开发一个 Angular 4 应用程序,但我遇到了一个问题,因为我必须在模型更改时调用 this.changeDetectorRef.detectChanges(); 来更新视图。例如,我有这个用于分页的代码:

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

我已明确将组件上的更改检测策略设置为ChangeDetectionStrategy.Default,但这没有效果。订阅 observable 时也会发生这种情况:

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 时,更改不会反映在HTML 中,除非我调用detectChanges()

【问题讨论】:

  • 原因可能不同:例如父组件有一个 onPush 策略,并且值被代理或例如该组件在 Angular 区域之外初始化。您应该在 plnkr 中复制它,并且在复制时您很可能会自己找到原因
  • 我觉得你可以试试ngOnChanges。您必须 @Input 子组件中的变量,它也会更新模板。
  • 你不必打电话,这是不对的。你能展示你的完整代码或创建一个 plunker 吗?
  • @smnbbrv 应用中没有使用 onPush 策略的组件。
  • @Maximus 我已将组件的代码添加到我的帖子中。

标签: angular typescript angular2-changedetection


【解决方案1】:

我已经解决了这个问题。

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 但问题出现在不受@Input 约束的ChildComponent 属性中。例如,我有一个changePage(pageNumber),但是当页码更新时,视图没有更新。
    • ngOnChanges 只能与@Input结合使用
    猜你喜欢
    • 1970-01-01
    • 2016-10-15
    • 2019-08-07
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 2022-11-24
    • 1970-01-01
    相关资源
    最近更新 更多