`ViewRef#onDestroy` throws an error in a ctor context
See original GitHub issueWhich @angular/* package(s) are the source of the bug?
core
Is this a regression?
No
Description
Already Chau said, ViewRef#onDestroy
is untouchable if the app is ONLY in dev mode.
https://twitter.com/Nartc1410/status/1527274445056126978
Repro: https://stackblitz.com/edit/angular-ivy-9mzqjg?file=src/main.ts
I’m not sure these are related, injecting ViewRef
by inject()
is impossible in the ctor context.
Please provide a link to a minimal reproduction of the bug
https://stackblitz.com/edit/angular-ivy-9mzqjg?file=src/main.ts
Please provide the exception or error you saw
Error: Uncaught (in promise): TypeError: Cannot add property 0, object is not extensible
TypeError: Cannot add property 0, object is not extensible
at TCleanup.push (<anonymous>)
at listenerInternal (https://angular-ivy-9mzqjg.stackblitz.io/turbo_modules/@angular/core@14.0.0-rc.1/fesm2015/core.mjs:15439:38)
Please provide the environment you discovered this bug in (run ng version
)
Angular v14.0.0-rc1
Anything else?
No response
Issue Analytics
- State:
- Created a year ago
- Reactions:3
- Comments:10 (7 by maintainers)
Top Results From Across the Web
No results found
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@lacolaco we had a conversation about this issue with the team. The
ChangeDetectorRef
class doesn’t provide theonDestroy
method as a public API, so in your example code you are using private APIs (by casting theChangeDetectorRef
toViewRef
). Since there is no public API to trigger the problem, I’m closing the ticket.@lacolaco thanks for reporting the issue and providing a repro.
I’ve simplified the repro a bit further and found out that the issue is not related to the
inject
function, but related to the timing of theonDestroy
call. Here is a minimal repro:https://stackblitz.com/edit/angular-ivy-jd7sx8?file=src%2Fapp%2Fapp.component.ts
The runtime code assumes that when the
ViewRef.onDestroy
function is invoked (typically in users code), the template is already processed and an internal data structure (responsible for storing the cleanup functions) becomes frozen as a way to avoid any accidental modifications (to retain the same shape of the structure, which is important for runtime performance):https://github.com/angular/angular/blob/c3205d0962f1ff0d2dd4fa26c70372f6fe80f5e3/packages/core/src/render3/instructions/shared.ts#L820-L826
However, this assumption is incorrect when the
ViewRef.onDestroy
is called from within a constructor (which happens in my repro) or during a class property initialization (which happens in the repro that you provided). I think thatObject.freeze
operation should have an additional check (possibly thetView.firstCreatePass
check).As a possible solution, you can try to delay the
onDestroy
call (for example, by wrapping it intoPromise.resolve().then(() => ref.onDestroy( ... ))
) - that’d allow component’s template to be fully processed before theObject.freeze
is invoked.