Angular 6.0.1.
This problem is manifesting itself inside a large application, but I created a simple component to try and see what is going on. The simple component has a simple template:
{{myProp}}
In the ngOnInit, I set this.myProp = 'hello';
and I see the word hello on screen as I would expect. So far so good.
However, if I now try to update the value of myProp
in a setTimeout
, it never updates the UI:
this.myProp = 'hello';
setTimeout(() => {
this.myProp = 'goodbye';
}, 3000);
The value shown in the UI is still hello.
If I inject ChangeDetectorRef
in my constructor and call cdr.detectChanges()
inside the timer, the UI updates.
Is this expected behavior, or what am I doing wrong? I wouldn't expect to have to call detectChanges
for this. I have not changed the ChangeDetectorStrategy
for the component so it is still default
.
Note, that in the "real" app, I'm not updating myProp
in a timer, but inside an Observable
subscription. The UI is not updating there and that is what has led me to investigate this and end at the timer as the simplest possible reproduction of the problem. As near as I can tell, updating the property value in any type of async manner is not showing the change in the UI.
Update
I think that my reference to setTimeout confused things. I was using that as a means of debugging. Instead of trying to rework this question, I posted a new question here (Angular interpolated value not updating on subscription) with a better explanation and the ngRx code that is causing me grief. Thanks.
Update #2
The problem was caused by a parent component having its ChangeDetectionStrategy
set to OnPush
. See the question I referenced above.
Thanks,
TTE
This is the expected action. The javascript method Window setTimeout is a
Window
command. This means that it is called outside the mainzone.js
thread (by which I mean the general change detection contained out of box in an Angular application), which is the expected plan. If you would like to contain your setTimeout() method you need to assign it to a variable contained inside your Angular TypeScript application.This behavior is the most distinct when using a similar method in the same family of functions called from
window
: the Window setInterval() MethodYou are able to contain this, and similar
Window
methods. The setTimeout() command needs theChangeDetectorRef
attached to it to detect changes in order to listen to Events Emitted. You can also insert commands by assigning the executed method to a component variable (similar to this answer on how to stop setInterval() after a component is destroyed here).