Angular 4 - “等待操作”的正确方法是什么?

时间:2017-04-17 18:20:42

标签: javascript angular

我遇到了一个简单的问题,它有setTimeout(...,0)的hacky解决方案。

看看这个简单的代码:

@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)做这个伎俩对我来说似乎有些苛刻,我宁愿不相信它。

问题:

Angular中“等待操作”的正确方法是什么? (所以我会看到“10”)?

Plnkr

1 个答案:

答案 0 :(得分:13)

1)您可以通过调用cdRef.detectChanges

强制Angular更新DOM
constructor(private cdRef: ChangeDetectorRef) {}

analyzeDom(){
  this.cdRef.detectChanges();
  alert($("div .mySpan").length)

<强> Plunker

因为setTimeout是macrotask因此它正在运行下一个摘要周期。 这意味着在调用setTimeout之后,将检查所有组件树

cdRef.detectChanges不会致电appRef.tick()。它只执行变更检测组件本身及其子项。

2)或者您可以等到Angulat通过订阅zone.onMicrotaskEmpty

更新DOM
import 'rxjs/add/operator/first';

constructor(private zone: NgZone) {}
...
this.zone.onMicrotaskEmpty.first().subscribe(() => this.analyzeDom());

注意:第一个操作符可能导致内存泄漏。请参阅https://github.com/angular/material2/issues/6905

订阅onMicrotaskEmpty不会调用更改检测周期

<强> Plunker