Angular 4 - 什么是“等待手术”的正确方法?
我遇到了一个简单的问题,它有一个简单的解决方案setTimeout(...,0)
。Angular 4 - 什么是“等待手术”的正确方法?
望着这个简单的代码:
@Component({
selector: 'my-app',
template: `
<div>
<input value='Fill Data' type='button' (click)='fill()'/>
<span *ngFor="let o of Items" class='mySpan'>Span To Detect<br></span>
</div>
`,
})
export class App {
Items:Array<number> = new Array<number>();
fill()
{
this.Items = [1,2,3,4,5,6,7,8,9,10]
this.analyzeDom(); //this has to run here
}
analyzeDom()
{
alert($("div .mySpan").length) // "0"
//BUT if I set this hacky trick , it works
// setTimeout(function(){ alert($("div .mySpan").length)},0) // "10"
}
}
如果我按一下按钮,警报显示为 “0”。我明白为什么会发生。这是因为Angular没有完成它的周期来实际填充ngFor
。
但是 - 使用setTimeout(..,0)
做这个诡计对我来说似乎有点冒失,我宁愿不相信它。
问:
什么是正确的方式在角 “等待作业”? (这样我会看到“10”)?
1)您可以强制角致电cdRef.detectChanges
constructor(private cdRef: ChangeDetectorRef) {}
analyzeDom(){
this.cdRef.detectChanges();
alert($("div .mySpan").length)
至于setTimeout
更新DOM是宏任务,因此它在运行下一个周期的消化。 这意味着在调用setTimeout
后,所有组件树都将被检查
cdRef.detectChanges
不会调用appRef.tick()
。它只执行变更检测组件本身及其子项。
2),或者你可以等到Angulat已经通过订阅更新DOM来zone.onMicrotaskEmpty
import 'rxjs/add/operator/first';
constructor(private zone: NgZone) {}
...
this.zone.onMicrotaskEmpty.first().subscribe(() => this.analyzeDom());
注:第一个运营商可能会导致内存泄漏。看看https://github.com/angular/material2/issues/6905
订阅onMicrotaskEmpty
不调用变更检测周期
你能解释如何不同'setTimeout(... 0)'是而不是你的解决方案? –
@Royi setTimeout的工作原理是因为它将您传递给它的函数碰撞到下一个评估周期。因此,在您的代码中进行更改,然后Angular检测到这些更改并相应地更改DOM。在通过代码之后,执行超时函数。真的不是一个很糟糕的解决方案,只是它不是一个Angular解决方案,因此很难。上面列出的解决方案明确表示在dom更新后执行我的代码。 – SethWhite
@SethWhite谢谢澄清,但是,我正在寻找一篇关于'onMicrotaskEmpty'的好文章(用于学习目的) - 仍然没有找到任何 –
通过使用[生命周期钩(https://angular.io/docs/ts/latest/guide/ lifecycle-hooks.html) - 'ngOnInit'或者不同的'ngDoCheck'方法 – mhodges
@mhodges但是点击按钮可以点击这个按钮,并且在这些钩子已经发生之后可以点击这个按钮 –
你想要的原因是什么使其同步和延迟功能,直到DOM将被更新?是不是更好地从当前模型读取长度,而不是像'alert(this.Items.length)'这样的DOM? – Kuba