angularjs 2 rc4变化检测:检查后表达发生变化

angularjs 2 rc4 Change detection: expression changed after it was checked

本文关键字:变化 检查 rc4 变化检测 angularjs      更新时间:2023-09-26

从rc1升级到rc4后,我得到以下异常:

表达式在检查后发生了更改。上一个值:"false"。当前值:"true"

在网上研究了这个问题并阅读了我所能阅读的所有内容后,我仍然不知道如何以"有角度"的方式(没有超时等)纠正这个问题。

  • 有用的线程:https://github.com/angular/angular/issues/6005

我知道在开发模式更改检测再次运行时,只是为了确保没有任何更改。我也明白,任何改变绑定的东西都"应该触发另一轮变化检测"。

我不明白的是为什么事件发生时不会自动触发新一轮检测,以及如何纠正。

我有一个非常简单的用例。最上面的组件负责显示外部UI。它还包含一个应该隐藏/显示的控件。此行为由激活的管线组件控制。

子实例化通过活动路由(路由器出口)进行,而不是手动进行。

因此,这个最顶端的组件和所有子组件都订阅了共享服务中的事件发射器并发送事件。

最顶端的组件也在其Oninit上订阅了此事件。当它接收到事件时,它会更改一个局部变量。这反映在该组件的html上。

AppComponent

export class AppComponent implements OnInit {
  hidePageControls:boolean = true;
  constructor(private apiService: ApiService) {}
  ngOnInit(): any {
    let me = this;
    this.apiService.hidePageControls.subscribe(value => me.hidePageControls = value);
  }
}

子组件

ngOnInit() {
    me.apiService.hidePageControls.emit(false);
}

这背后的原理是,当用户导航到应用程序的不同部分时,会使用不同的组件。然后,这些组件将事件发送到最上面的组件,以显示/隐藏特定控件。

我读过这个问题的可能解决方案,包括setTimeout(),直接调用更改检测等。人们也说我们不应该"对抗"框架,我同意这一点。

因此,请让我知道我认为子组件通知父组件是否是"错误的"角度思维方式,并尽一切努力让我知道这样做的"角度"方式会是什么样子。


编辑

对于这种类型的错误,我找到的唯一解决方案是使用这样的超时:

拆下变化检测器。当事件被手动触发时,触发一轮更改检测。

constructor(private apiService: ApiService, private categoryService: CategoryService, private router: Router, private cd: ChangeDetectorRef) {
    this.cd.detach();
}
.
.
.
.
this.apiService.hidePageControls.subscribe(value => {
    me.hidePageControls = value;
    setInterval(() => {
        me.cd.detectChanges();
    }, 100);
});

据我所知,这将导致在由于超时而完成额外的开发更改检测运行后进行更改检测。我发现这是一个挑剔的解决方案。

如果有更好的,请告诉我。

我使用了几乎类似的方式来根据子元素决策启用/禁用控制。在角度更新(rc1->rc4)之前,它就像一个符咒。更新后,组件在第一次加载时就开始中断。突破性变化是:

facade:将EventEmitter更改为默认同步(#8761)(e5904f4)

发布的链接

在子组件的初始化过程中,父组件的值在其更改检测回合完成后发生更改。


修复您的问题可能是:

// in apiService
hidePageControls = new EventEmitter(true);

EventEmitter构造函数中的True将强制其为异步

希望能有所帮助。

Angular不喜欢变化检测导致模型变化。

CCD_ 1由变化检测调用。

您可以使用setTimeout()延迟更改,直到更改检测完成。setTimeout()导致应用程序范围内的更改检测运行,因此是不可取的。

您可以使用变更检测未调用的另一个生命周期回调

据我记忆所及,ngAfterViewInit适用于这种情况。

ngAfterViewInit() {
    me.apiService.hidePageControls.emit(false);
}

另一种方法是注入ChangeDetectorRef并显式调用更改检测,以使Angular在抛出更改之前意识到更改:

constructor(cdRef: ChangeDetectorRef) {}
ngOnInit() {
    me.apiService.hidePageControls.emit(false);
    this.cdRef.detectChanges();
}