-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Description
Which @angular/* package(s) are relevant/related to the feature request?
elements
Description
I would like to be able to destroy the injector used to define a custom element, and replace it with a new instance.
For example, if a host application uses a custom element on one page, it would be useful to be able to completely destroy that custom element's injector (and all created root services) when leaving the page. For large complex apps, this can help keep memory usage low when navigating through the application.
Proposed solution
Injector Factory
I think this could be accomplished by allowing applications to provide an injector factory to createCustomElement. When a new element is created, it can use the factory to get the injector for the component. This would allow an application to destroy an injector when it knows no instances of the custom element are on the page (such as in a single-spa unmount hook). It can then lazily initialize a new injector when appropriate.
export type NgElementConfigStaticInjector = {
injector: Injector
};
export type NgElementConfig InjectorFactory= {
injectorFactory: () => Injector
};
export type NgElementConfig = (NgElementConfigStaticInjector | NgElementConfigInjectorFactory) & {
strategyFactory?: NgElementStrategyFactory;
}An alternative may be to expose the ComponentNgElementStrategyFactory used internally. This way, applications can reuse the default implementation but provide a different injector than the initial one. This isn't as "clean" of an approach, in my opinion.
Challenge: observedAttributes
The custom elements implementation requires defining a static array of attribute names which trigger lifecycle hooks on the custom element. Angular uses the component inputs for the observed attributes.
Currently, the provided injector is used to compute the inputs defined by the component using the ComponentFactoryResolver in the injector. I am not sure if it would be problematic to continue to use the original list of observed attributes if the injector changes. A new injector could technically define its own component factory which reports different inputs each time, but such a case would be very unusual.
Component inputs shouldn't in theory be dependent on the injector used to create the component.
Alternatives considered
Un-registering custom elements
Since the web platform doesn't provide a way to "un-register" custom elements, it isn't possible to change the ng element constructor assigned to an element tag.
Passing a config object where injector is a getter
This is hacky, and doesn't work because the inner system stores its own reference to the injector to pass it to the NgElementStrategyFactory for each new component instance.
Custom NgElementStrategyFactory
This is not practical to do, because the default implementation is both private (can't be extended or reused), and relies on internal APIs inside Angular to work properly.