在Angular中手动触发变更检测


387

我正在编写一个具有属性的Angular组件Mode(): string

我希望能够以编程方式设置此属性,而不响应任何事件。

问题在于,在没有浏览器事件的情况下,模板绑定{{Mode}}不会更新。

有没有办法手动触发此更改检测?

Answers:


640

尝试以下方法之一:

  • ApplicationRef.tick()-与AngularJS类似$rootScope.$digest()-例如,检查完整的组件树
  • NgZone.run(callback)-类似于$rootScope.$apply(callback)-即,在Angular区域内评估回调函数。我认为,但我不确定,这最终在执行回调函数后检查整个组件树。
  • ChangeDetectorRef.detectChanges()-类似于$scope.$digest()-即,仅检查此组件及其子项

您可以将ApplicationRefNgZoneChangeDetectorRef注入到组件中。


1
谢谢,我选择了第三个解决方案,以免检查所有内容,因为更改相当本地化。当我有更多时间时,我应该研究其他选项。每个选择是否会对性能产生影响?
jz87 '16

36
为+1 ChangeDetectorRef.detectChanges()。验证程序在我的指令可以更新输入值之前触发。
ps2goat

7
在2.0.0 final中仍存在ApplicationRef.tick()和ChangeDetectorRef.detectChanges()。
Max Mumford

51
只是以为我会提到这一点。这些不是静态方法,它们是实例方法。您将需要将这些类作为服务注入。
斯蒂芬·保罗

1
ApplicationRef.tick()帮助解决了FireFox v17(<20)的问题
Dan J

123

我使用了公认的答案参考,并想举一个例子,因为Angular 2文档非常难读,我希望这会更容易:

  1. 导入NgZone

    import { Component, NgZone } from '@angular/core';
    
  2. 将其添加到您的类构造函数

    constructor(public zone: NgZone, ...args){}
    
  3. 使用zone.run以下代码运行代码:

    this.zone.run(() => this.donations = donations)
    

6
您应该将zone.run代码放在哪里,究竟是donations什么?
suku 2017年

@suku捐赠是您要更新的任何属性,因此可能是this.foo = bar。zone.run可以在任何您想更新内容的地方进行。
马修Optional Meehan,2017年

4
我在使用document.addEventListener(“ resume”,callback)时使用此解决方案强制视图更新
marcovtwout

71

我可以用markForCheck()更新它

导入ChangeDetectorRef

import { ChangeDetectorRef } from '@angular/core';

注入并实例化它

constructor(private ref: ChangeDetectorRef) { 
}

最后进行标记更改检测

this.ref.markForCheck();

这是markForCheck()有效而detectChanges()不起作用的示例。

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

编辑:本示例不再描述问题了:(我相信它可能正在运行已修复的较新Angular版本。

(按STOP / RUN重新运行)


好点,detectChanges()不起作用。我注意到了相同的问题,并发现如果更改检测不是OnPush,它就可以工作。对此做出解释将是一件好事……
基督教徒

2
似乎detectChanges实际上在这个插件中起作用?我想念什么吗?
Jared_C

1
您应注意,ChangeDetectorRef仅在组件中有效
kevinius

(!)这是一个不好的例子,对不起。示例不显示任何内容。第一项只是被覆盖。只是稍微调整一下计时器...
Peter Stegnar

这个例子没有再描绘的问题:(我认为它可能会运行一个新的角度版本在那里的固定。
努诺·托马斯

7

在Angular 2+中,尝试@Input装饰器

它允许在父组件和子组件之间进行一些不错的属性绑定。

首先在父级中创建一个全局变量,以保存将传递给子级的对象/属性。

接下来,在子级中创建一个全局变量,以保存从父级传递来的对象/属性。

然后在使用子模板的父html中,添加带有子变量名称的方括号符号,然后将其设置为等于父变量的名称。例:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

最后,在子组件中定义子属性的地方,添加Input装饰器:

@Input()
public childVariable: any

当您的父变量更新时,它应该将更新传递给子组件,子组件将更新其html。

另外,要触发子组件中的功能,请查看ngOnChanges。


2
不...那是问题...如果您在父母中进行更新...例如exmaple是通过静态方法“通过引用”进行更新的,则子代不会将其捡起,因为还没有发生更改检测
Bhail

我几天来遇到同样的问题。我尝试从PHP后端检索数据,并且数据根本不更新。在Microsoft Edge上可以正常使用,但在其他浏览器上则不能。我一直在获取我刚开始使用的数据,但是如果数据发生更改,它就不会在视图上更新
el6976

1

ChangeDetectorRef.detectChanges()-与$ scope。$ digest()类似-即,仅检查此组件及其子级

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.