Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Angular Elements Lifecycle is Broken #64229

@dgp1130

Description

@dgp1130

Which @angular/* package(s) are the source of the bug?

elements

Is this a regression?

No

Description

I believe the current lifecycle of Angular Elements is fundamentally flawed.

Custom elements really have two lifecycle methods which are relevant here:

  • connectedCallback - Element is attached to the DOM.
  • disconnectedCallback - Element is detached from the DOM.

Note that an element may be reattached at any time after being detached. "Destroy" of an element just involves detaching it and dropping all references, allowing the GC to reclaim that element.

This is notable, because it means there is no explicit "destroy" interaction. Any given disconnect could be followed by a subsequent attach and any arbitrary time in the future, or could be reclaimed by the GC. There's fundamentally no way to know.

The role of Angular Elements is to translate these semantics into something reasonable for existing Angular components.

Currently on connectedCallback we create a component and attach it to the ApplicationRef. On disconnectedCallback we destroy that component. In theory, reattach should then recreate the component, though that's a little broken right now.

I think this is flawed, because it loses any internal component state as part of the destroy process. We need the component to be inert and disabled but able to be reactivated in the future if it is reconnected. Basically, custom elements want an activate/deactivate lifecycle, but Angular only provides a destroy lifecycle, with no way to "undestroy" a component.

I think ideally:

  • connectedCallback() should just call appRef.attachView (plus createComponent on first connect).
  • disconnectedCallback() should just call appRef.detachView to deactivate it.

In this model, each reattachment to the DOM is just a pair of attachView and detachView calls managing its relationship with the ApplicationRef and the overall app lifecycle. When detached, the component should be inert and eligible for GC if not otherwise referenced. I'm not sure if that's actually possible today though or if you have to call ComponentRef.prototype.destroy to break some reference which would otherwise retain it.

We would probably need new ngOnConnected and ngOnDisconnected lifecycle hooks which would allow a component to acquire and release resources compatible with this model. Otherwise a component containing a simple timer would never be reclaimable, this mechanism would be necessary to disable/re-enable the timer when the component is removed/readded. These hooks need to be available for every component, not just the root component converted into a custom element, since any of them might be rendered as a descendant of the custom element.

One more challenge is that there is no appropriate time to call ngOnDestroy since we don't know a component should be destroyed until it gets GC'd. We'd either need to remove this hook altogether, or potentially link the Angular component to its custom element via a WeakRef and use a FinalizationRegistry to detect when the custom element is reclaimed and call ComponentRef.prototype.destroy in response. I'm very loathe to expose GC timing into application logic, but I don't think there's any other opportunity to do this.

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/stackblitz-starters-qogge9cd?description=An%20angular-cli%20project%20based%20on%20@angular/animations,%20@angular/common,%20@angular/compiler,%20@angular/core,%20@angular/forms,%20@angular/platform-browser,%20@angular/platform-browser-dynamic,%20@angular/router,%20core-js,%20rxjs,%20tslib%20and%20zone.js&file=src%2Fmain.ts,src%2Findex.html&template=node&title=Angular%20Starter

Please provide the exception or error you saw


Please provide the environment you discovered this bug in (run ng version)

v20

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: elementsIssues related to Angular Elements

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions