angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
95.94k stars 25.36k forks source link

ViewChildren's QueryList.changes doesn't detect changes #12283

Closed timblakely closed 7 years ago

timblakely commented 7 years ago

I'm submitting a ...

[x ] bug report 
[ ] feature request
[ ] support request

Current behavior When subscribing to QueryList.changes created by a ViewChild, any changes to bound variables are not detected.

Expected behavior 1) Template to be updated 2) If this is WAI, the debug change detector should detect that a bound variable was changed and throw, similar to updating bound variables in ngAfterViewChecked.

Minimal reproduction of the problem with instructions Plunker

DzmitryShylovich commented 7 years ago

This is how change detection works in angular. See explanation http://stackoverflow.com/a/35243106

timblakely commented 7 years ago

@DzmitryShylovich I'm well aware of how change detection works. In this case Angular fills out ViewChildren after the view is checked - in which case updating the template is forbidden - but a template modification doesn't result in the appropriate debug warning. In addition, the compiler might be able to batch these calls and launch the change handlers via Zone.scheduleMicroTask, though I'm not sure about the any guarantees QueryList.changes makes in terms of when or where the observable is emitted, as it's undocumented.

vicb commented 7 years ago

Thanks for attaching a plunker.

Can you describe:

timblakely commented 7 years ago

Sure!

Expected: Clicking the "Populate!" button adds a child component Foo, gated by an *ngIf directive. A ViewChildren-generated QueryList.changes observable is subscribed to that should add a message to the template an array when an event arrives. The message says "A '' element was added"

Actual: When the button is clicked, the Foo component appears. The .changes event is fired, and the message is added to the template. However, the change detection is not run, causing a disconnect between the model and the template. The disconnect can be rectified by clicking the other button to force change detection via ChangeDetectorRef.markForCheck. No warning message about changing after it was checked is shown.

Desired: Any other observable I've ever used that changes the template in the .subscribe function correctly causes change detection to occur. A QueryList generated via ContentChildren works just fine (new plunker), so I suspect this has to do with the timing of the ViewChildren's query firing after content checking as opposed to in a new microTask.

rupebac commented 7 years ago

I am experiencing similar problems. Sounds pretty serious to me (and similar to #10962 ?)

Real case scenario for me:

<tabs-panel #tab>
     <template newTab>
         <tab title="TabTitle {{ tab.numberTabs() }}">
               content for new tabs
         </tab>
    </template>
</tabs-panel>

When the template gets projected at any time with createEmbeddedView(...), the @ViewChildren(Tab) query that I have at TabsPanel does not get notified with the new tab.

tbosch commented 7 years ago

This is actually legit, as we can determine the content of @ViewChildren earlier so that you can still change content in the view.

tbosch commented 7 years ago

@lqbweb See #12712, although you would need a @ContentChildren to get the tabs...

angular-automatic-lock-bot[bot] commented 5 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.