stencil icon indicating copy to clipboard operation
stencil copied to clipboard

bug: watch decorator doesn't work if we change the original tag name

Open urielblanco opened this issue 3 years ago • 3 comments

Prerequisites

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

urielblanco avatar Aug 25 '22 11:08 urielblanco

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!

urielblanco avatar Aug 25 '22 11:08 urielblanco

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!

tanner-reits avatar Aug 25 '22 15:08 tanner-reits

@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.

christian-bromann avatar May 14 '24 17:05 christian-bromann

A fix for this was released as a part of Stencil's v4.18.2 release!

tanner-reits avatar Jun 20 '24 16:06 tanner-reits