angularjs 2 rc4更改检测:检查后表达式发生了变化

时间:2016-07-23 10:39:08

标签: javascript angularjs angular expression detection

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

Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'

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

我理解再次运行开发模式更改检测时,只是为了确保没有任何更改。我也明白,改变绑定的所有内容都应该触发另一轮变更检测。

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

我有一个非常简单的用例。最顶层的组件负责显示外部UI。它还包含一个应隐藏/显示的控件。此行为由活动路由组件控制。

子实例化由活动路由(路由器插座)发生,而不是手动。

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

最顶级的组件也在它的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);
  }
}

ChildComponent

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);
});

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

如果存在更好的一个,请告诉我。

2 个答案:

答案 0 :(得分:1)

我使用几乎相似的方式启用/禁用控制,具体取决于子元素决策。 在角度更新(rc1-> rc4)之前,它就像一个魅力。更新后,组件在首次加载时开始中断。 突破性变化是:

  

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

link to issue

父组件值在子组件的初始化期间完成更改检测轮次后发生更改。

您的问题的

修复可能是:

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

在EventEmitter构造函数中为True将强制它为异步

希望它能提供帮助。

答案 1 :(得分:0)

当角度变化检测导致模型发生变化时,Angular并不感兴趣。

通过更改检测调用

String url = "https://www.google.pt/"; CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); CustomTabsIntent customTabsIntent = builder.build(); customTabsIntent.launchUrl(this, Uri.parse(url));

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

您可以使用未通过更改检测调用的其他生命周期回调

据我记得setTimeout()适用于此案例。

ngAfterViewInit

另一种方法是注入ngAfterViewInit() { me.apiService.hidePageControls.emit(false); } 并明确调用更改检测,以使Angular在抛出之前知道更改:

ChangeDetectorRef