This is because you're breaking the Angular change detection cycle.
Here is what is happening after you click on your first toggle button :
1- You click on the toggle
2- ZoneJS, which has hooks in click events gets notified (Simply put)
3- Zone makes sure the click event is finished
4- Zone will let Angular know that an async
event has happened, we must check the component and make sure that the view ( DOM ) is reflecting the model ( the model/the javascript world). So change detection
will run, and it will detect all the changes and finds that there are bindings in the template (ng-if
).
5- After ngIf
becomes true, AND NOTE THAT THIS IS ALL SYNC SO FAR, the ng-container
gets created and your templateOutlet
gets created and your hello
component will be rendered.
NOTE AGAIN : this is all sync.
6 - View has been updated, change detection is now off the hook.
7 - Inside your hello
component you fire another event which is the created
and that notifies the Parent component and inside your parent component you are mutating the array, and Angular doesn't care about that because there hasn't been a async event, nor have you updated any of the inputs, you've just fired another sync event after change detection was finished his job.
8- the Array is now updated, but the view is not ( in the parent component)
9 - You click again, the same happens and Angular updates the parent view in the first change detection run and you see the array is being reflected in the view.
To prove that I'm right :D :
onTemplateCreated() {
console.log('Got the event from chil');
this.template.push('Template created');
console.log('this.template',this.template);
}
You'll see that after click , the console is showing the right array, but the view is not untill you click again.
Now let's swich to my code
onTemplateCreated() {
console.log('Got the event from chil');
this.template = [...this.template,'Template created'];
}
BEcause I'm not mutating and the refrence is being updated, Angular now has to care about this change, BUT there's still an issue, Angular's change detector was finished and you updated the model withouth running any async
event, so we're in trouble, because Angular doesn't like the model to be updated after the change detection is finished,
So you'll be thrown an error that says :
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value
To fix that, first read my other post to understand it, second, you need tell Angular that you know what you're doing and run the change detection manually :
this._cd.detectChanges
OR , you can make it async :
onTemplateCreated() {
console.log('Got the event from chil');
setTimeout(()=>{
this.template = [...this.template,'Template created'];
})
}