为什么我需要使用默认的变更检测策略调用detectChanges()方法?
为什么我需要使用默认的变更检测策略调用detectChanges()方法?
我正在开发一个Angular 4应用程序,但是我遇到了一个问题,即当模型发生变化时,我需要调用this.changeDetectorRef.detectChanges();
来更新视图。例如,我有这段代码用于分页:
changePage(pageNumber) { this.currentPage = pageNumber; // 为什么需要这样做? this.changeDetectorRef.detectChanges(); }
我已经在组件上明确设置了变更检测策略为ChangeDetectionStrategy.Default
,但是这没有任何效果。当订阅一个可观察对象时,也会发生这种情况:
showResults(preference) { this.apiService.get('dining_autocomplete/', `?search=${preference}`) .subscribe((results) => { this.searchResults = results; // 为什么需要这样做? 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; // 为什么需要这样做? this.changeDetectorRef.detectChanges(); } }
当调用changePage()
并更新this.currentPage
时,如果不调用detectChanges()
,HTML中的更改不会反映出来。
为什么我需要使用默认的变更检测策略调用detectChanges()?
在解决这个问题之前,我遇到了一个组件间的通信问题。另一个组件向该组件发送通知,但是在Angular区域之外运行Observable.fromEvent(),因此无法自动触发变更检测。在解决这个问题的过程中,我参考了关于zones的这篇文章和这个StackOverflow帖子上的解决方案。
在这个问题中,通过调用detectChanges()方法来手动触发变更检测是解决的办法。这个方法会强制Angular检查模型的变化并更新视图。在默认的变更检测策略下,Angular会自动调用detectChanges()方法,但是由于在Angular区域之外运行Observable.fromEvent(),导致变更检测无法自动触发。
通过调用detectChanges()方法,我们可以手动触发变更检测,并确保模型的变化能够及时反映到视图上。这样就可以解决视图不更新的问题。
需要注意的是,调用detectChanges()方法可能会增加应用程序的性能开销,因为它会触发整个组件树的变更检测。因此,我们应该谨慎使用这个方法,只在必要的情况下调用。
总结一下,当遇到组件间通信导致视图不更新的问题时,我们可以考虑使用默认的变更检测策略,并调用detectChanges()方法来手动触发变更检测。这样可以确保模型的变化能够及时反映到视图上,解决视图不更新的问题。同时,我们还应该注意谨慎使用detectChanges()方法,以避免不必要的性能开销。
为什么需要使用默认的变更检测策略时需要调用detectChanges()?
在上述代码中,我们将searchResults属性通过父组件的模板传递到子组件中,并在子组件的模板中使用它。当searchResults属性发生变化时,子组件会自动更新并显示新的值。
然而,问题出现在子组件中没有通过绑定方式绑定的属性上。例如,当页码发生变化时,视图并没有被更新。
这是因为ngOnChanges()方法只在与绑定结合使用时才起作用。在没有绑定的情况下,Angular的变更检测系统无法自动检测到属性的变化并更新视图。
解决这个问题的方法是手动调用detectChanges()方法来触发变更检测。在子组件中,我们可以在属性发生变化时调用detectChanges()方法来更新视图。
下面是解决方法的示例代码:
export class ChildComponent implements OnChanges {
@Input() searchResults;
constructor(private changeDetectorRef: ChangeDetectorRef) { }
ngOnChanges() {
// some code
// 手动调用detectChanges()方法来更新视图
this.changeDetectorRef.detectChanges();
}
}
通过调用detectChanges()方法,我们可以手动触发变更检测并更新视图。这样,即使没有通过绑定方式绑定的属性也能够在发生变化时更新视图。
总结起来,当我们需要在子组件中更新没有通过绑定方式绑定的属性时,需要手动调用detectChanges()方法来触发变更检测。这样可以确保视图能够正确地更新并显示最新的值。