Skip to content

ComponentRef Change detector doesn't trigger detecting for view #36667

Closed

Description

@rolginroman

🐞 bug report

Affected Package

The issue is caused by package @angular/core

Is this a regression?

Cannot say

Description

Component created by #ComponentFactoryResolver.
ComponentFactoryResolver#createComponent returns ComponentRef that does have changeDetectorRef.
After any changes to component's input by code (not by template) and invocation of such ComponentRef#changeDetectorRef.detectChanges component's view won't be updated.

example from repro: dynamic-wrapper.component.ts#createComponent.

componentRef.changeDetectorRef.detectChanges()

This is root issue.

To testing purposes ChangeDetectorRef was be added to component's constructor and invoked by
consumer of this ComponentFactoryResolver. CDR from component's injector works as expected

example from repro: dynamic-wrapper.component.ts#createComponent

componentRef.instance.cdr.detectChanges()

🔬 Minimal Reproduction

StackBlitz

GitHub repro repository:
https://github.com/RolginRoman/ng-dynamic-components-cdr-repro

🔥 Exception or Error


No exception

🌍 Your Environment

Angular Version:



 Angular version 9.1.0

Anything else relevant?

Seems like browser, OS version or anything else doesn't matter

Activity

  1. added this to the needsTriage milestone on Apr 16, 2020
  2. pkozlowski-opensource commented on May 26, 2020

    @pkozlowski-opensource
    Member

    This is a confirmed bug that still happens in the Angular v9 with ivy enabled (the same bug is present in VE). Here is a simplified reproduce scenario: https://stackblitz.com/edit/angular-i8tus5?file=package.json

    What is going on here is that changeDetectorRef on a ComponentRef points to the change detector of the root (host) view of a dynamically created component. Then, inside the host view we've got the actual component view, but the component view is OnPush thus we never refresh it!

    While it works as implemented (and as was implemented in VE), this behaviour is very confusing to the users and I would consider this to be broken from a user perspective. To actually understand why it doesn't work one needs to deeply understand inner workings of Angular (concept of the host view, OnPush etc.). I'm not sure what is the best long terms solution here but the fix won't be trivial.

    The good news is that work-arrounds exists - the simplest one would be to remove ChangeDetectionStrategy.OnPush from the dynamically created component - this is what I would recommend for now @rolginroman .

  3. modified the milestones: needsTriage, Backlog on May 26, 2020
  4. pkozlowski-opensource commented on May 26, 2020

    @pkozlowski-opensource
    Member

    BTW, this issue will be very visible for people trying to test OnPush components - in fact this issue was already reported for TestBed as #12313 - it is currently highly up-voted and commented on issue biting people in practice.

  5. rolginroman commented on May 26, 2020

    @rolginroman
    Author

    @pkozlowski-opensource thanks for your feedback! 🙂

    Is it leads us to 'not to use onPush with dynamic components at all'?
    From my perspective such behaviour completely breaks many applications of dynamically-created components (from simple to advanced cases).
    Component (or dev 😊) should be smart enough to understand where component will be created (from template or from such factories)

    yeap, without OnPush it can work but it can affect app performance if there are many such components, can't it? Possible WA for it: detach CD from components and control CD cycles by self?

  6. 13 remaining items

  7. added a commit that references this issue on Nov 4, 2020
    6003457
  8. jgomesmv commented on Mar 12, 2021

    @jgomesmv

    I'm also facing this issue on angular 11.0.8. You can find a minimal reproduction here:
    https://stackblitz.com/edit/angular-ivy-componentfactory-onpush-issue

    Hope it helps!

  9. proambb commented on Sep 24, 2021

    @proambb

    Workarroud Is to use component's injector to get Real ChangeDetectorRef.

    ComponentRef.injector.get(ChangeDetectorRef)

    In my case the following code helped

    this.componentRef.injector.get(ChangeDetectorRef).detectChanges();
    
  10. hoeni commented on Dec 13, 2021

    @hoeni

    Hell, this took me some time to find out this is an Angular issue (NG 13), not mine. But at least the workaround to get a fresh CDR from the injector worked well for me!

  11. montella1507 commented on Dec 13, 2021

    @montella1507

    @pkozlowski-opensource as far as this bug is not yet fixed - can we atleast add note - warning, for example there:

    https://angular.io/guide/dynamic-component-loader

    that component's change detector is often not resolved 100% correctly and its recommended to use components injector to resolve Change detector?

  12. pkozlowski-opensource commented on Jul 4, 2022

    @pkozlowski-opensource
    Member

    This was just fixed via #46641 - the ComponentRef has a new method - setInput that correctly sets an input and makes sure that change detection is properly invoked. More details in #46641

  13. angular-automatic-lock-bot commented on Aug 4, 2022

    @angular-automatic-lock-bot

    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.

  14. locked and limited conversation to collaborators on Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions