Angular 4 - Каков правильный способ "ждать работы"?
Я столкнулся с простой проблемой, которая имеет хакерское решение setTimeout(...,0)
.
Посмотрите на этот простой код:
@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
1) Вы можете заставить Angular обновить DOM, вызвав cdRef.detectChanges
конструктор (private cdRef: ChangeDetectorRef) {}
analyzeDom() { this.cdRef.detectChanges(); alert ($ ( "div.mySpan" ). length)
Код>
Plunker
Поскольку setTimeout
является макрозадачей, поэтому он запускает следующий цикл дайджеста.
Это означает, что после вызова setTimeout
будет проверено все дерево компонентов
cdRef.detectChanges
не вызывает appRef.tick()
. Он выполняет только компонент обнаружения изменений и его дочерние элементы.
2), или вы можете подождать, пока Angulat не обновит DOM, подписавшись на zone.onMicrotaskEmpty
import 'rxjs/add/operator/first';
конструктор (частная зона: NgZone) {}
...
this.zone.onMicrotaskEmpty.first(). subscribe (() = > this.analyzeDom());
Код>
Примечание: первый оператор может вызвать утечку памяти. См. https://github.com/angular/material2/issues/6905
Подписывание onMicrotaskEmpty
не вызывает цикл обнаружения изменений
Plunker