Angular Elements should preserve/forward component methods
See original GitHub issueI’m submitting a…
- Regression (a behavior that used to work and stopped working in a new release)
- Bug report
- Feature request
- Documentation issue or request
- Support request
Partially considered a bug due to developer expectations, partially a feature request because it might not be “fixable” in that sense.
Current behavior
When creating Custom Elements from Angular Components using Angular Elements APIs, the resulting elements do not preserve the Angular component methods on the Custom elements.
For example giving a component like this:
@Component(...)
export class CarComponent {
drive() {...}
}
does not make drive()
available on the resulting custom element:
const car = document.querySeletor('car-thing');
car.drive(); // Errors out because `drive()` doesn't exist on <car-thing>
This is because an Angular component doesn’t actually “become” the Custom Element but is rather preserved “inside” the Custom Element and readable via componentRef
. To make the code above work we’d need to call
car.componentRef.instance.drive();
Expected behavior
As Angular Elements are being promoted as Angular Components packaged as Custom Elements, I’d expect Angular Elements to have the same characteristics (Custom Elements come with their attributes, properties, methods and events).
In other words, I’d expect this to work:
car.drive(); // Angular takes care of preserving or forward API methods
Some useful notes and ideas on this
I’ve talked to @gkalpak about this already and one of his ideas was to maybe come up with a new decorator that tells Angular to preserve the decorated method on the resulting host element.
Another idea would be to declare in the registration process which methods should be preserved/forwarded. This could look like this:
registerAsCustomElements([{component: CarComponent, methods: ['drive']}], ...)
The reason there might be an additional API for this needed is because we can’t just preserve/forward all of the components methods. Some methods may not be intended to be available on the resulting Angular Element (e.g. lifecycle hooks etc.)
What is the motivation / use case for changing the behavior?
I think it’d be great if consumers of Angular Elements don’t have to worry about Angular internals and can in fact use any Angular Element exactly the same way they’d use any other DOM element. Right now, to call component methods, consumers of Angular Elements have to know that those are populated on componentRef.instance
, which doesn’t seem to be very convenient nor what one would expect.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:28
- Comments:23 (7 by maintainers)
FWIW:
Here is a different approach that I used to work around this issue, I found it more palatable than the
@Input
solution as it feels a bit less like it’s abusing side effects of Angular’s design.Using the car example from the OP:
I manually ‘exposed’ the functions on the native element in the constructor like so:
This allowed me to then call the function without issue:
I like this approach as it feels a bit more ‘intentional’ and self documenting by declaring the ‘public’ methods in the constructor upfront. Additionally if you wanted you could wrap them in more defensive checks to make sure you’re not clobbering functions with the same name that are already present on the nativeElement. This could provide a decent amount of backwards compat if you ever bumped up to a version of angular that resolved this issue.
I’m not an angular wizard though so if someone see’s an issue with this approach let me know!
Any news here ? I see it was put to backlog 😃.
@aukris BTW you can use methods using
Input
, but you have to write it one of the following ways:or