bug: watch decorator doesn't work if we change the original tag name
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Stencil Version
2.13.0
Current Behavior
My problem is that the @Watch decorator only works if I keep the original tag name.
- If I import a custom element from my stencil library and define it as a custom element like this:
My vanilla js app
import { MyComponent } from '@my-lib/dist/components/my-component.js';
customElements.define('my-component', MyComponent);
My simple component
import { Component, Prop, h, Watch } from '@stencil/core';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true,
})
export class MyComponent {
/**
* The first name
*/
@Prop({ reflect: true, mutable: true }) checked?: boolean = false;
@Watch('checked')
onValueChange(): void {
console.log('trigger from watch', this.checked);
}
private readonly onChange = (e: InputEvent): void => {
const isElementChecked = (e.target as HTMLInputElement).checked;
if (isElementChecked !== this.checked) {
this.checked = isElementChecked;
}
};
render() {
return <input onChange={this.onChange} type="checkbox" name="test" id="" />;
}
}
With this example, I can see in the console that the watch func triggered 🙌🏽
Expected Behavior
Suppose I change the original tag name when I define my component in customElement.define() I hope that the @Watch decorator keeps working but it doesn't.
Steps to Reproduce
You can recreate my example in Current behavior or download it and run the scripts like this:
npm i
npm run build
npm run start:test
And that's it! If you change the tag name from "my-component" to "my-component-test" the watch func stop working and you can't see in the console my message.
Code Reproduction URL
https://github.com/urielblanco/test-watch
Additional Information
No response
The community in slack was help me and one guy said that the problem is here
https://github.dev/ionic-team/stencil/blob/c05cebec911ca0ef4acf7e4673e24e7801316b0d/src/runtime/initialize-component.ts#L87-L88
customElements.whenDefined(cmpMeta.$tagName$).then(() => (hostRef.$flags$ |= 128 /* isWatchReady */));
$tagName$ is defined in your file as "my-component", so this callback never fires
Then
https://github.dev/ionic-team/stencil/blob/c05cebec911ca0ef4acf7e4673e24e7801316b0d/src/runtime/set-value.ts#L53-L54
if (BUILD.watchCallback && cmpMeta.$watchers$ && flags & HOST_FLAGS.isWatchReady) {
is always false (meaning the watch is never triggered
Looks like changing:
customElements.whenDefined(cmpMeta.$tagName$).then(() => (hostRef.$flags$ |= 128 /* isWatchReady */));
to
customElements.whenDefined(elm.localName).then(() => (hostRef.$flags$ |= 128 /* isWatchReady */));
makes it work, but maybe it breaks things elsewhere
I hope this could help!
Hi @urielblanco 👋
Thanks for reporting this issue and the additional context to problematic code! I was able to verify the problem in your reproduction repo. I'll go ahead and get this labeled appropriately so we can get this refined and into our backlog. Thanks again!
@urielblanco thanks for providing the solution to this bug. I raised a PR in https://github.com/ionic-team/stencil/pull/5767 to bring this into Stencil.
A fix for this was released as a part of Stencil's v4.18.2 release!