8

I'm struggling to get @Method in stenciljs working - any help would be appreciated.

Here's my component code with a function called setName that I want to expose on my component:

import { Component, Prop, Method, State } from "@stencil/core";

@Component({
  tag: "my-name",
  shadow: true
})
export class MyComponent {

  @Prop() first: string;
  @Prop() last: string;
  @State() dummy: string;

  @Method() setName(first: string, last: string): void {
    this.first = first;
    this.last = last;
    this.dummy = first + last;
  }
  render(): JSX.Element {
    return (
      <div>
        Hello, World! I'm {this.first} {this.last}
      </div>
    );
  }
}

Here's the html and script that references the component:

<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
  <title>Stencil Component Starter</title>
  <script src="/build/mycomponent.js"></script>

</head>
<body>

  <my-name  />

  <script>
    var myName = document.querySelector("my-name");
    myName.setName('Bob', 'Smith');
  </script>
</body>
</html>

Here's a screen shot of the error I'm getting which is Uncaught TypeError: myName.setName is not a function:

enter image description here

Carl Rippon
  • 4,553
  • 8
  • 49
  • 64

3 Answers3

13

Methods are not immediately available on a component; they have to be loaded/hydrated by Stencil before you can use them.

Components have a componentOnReady function that resolve when the component is ready to be used. So something like:

var myName = document.querySelector("my-name");
myName.componentOnReady().then(() => {
  myName.setName('Bob', 'Smith');
});
matthewsteele
  • 1,797
  • 1
  • 15
  • 31
  • 1
    Unfortunately, this doesn't work. I get "Uncaught TypeError: myName.componentOnReady is not a function" – Carl Rippon May 12 '18 at 17:15
  • 3
    Correction - after updating to stencil 0.8.2 this worked! – Carl Rippon May 12 '18 at 17:18
  • @CarlRippon here is the reason why it worked after upgrading to stencil https://github.com/ionic-team/stencil/blob/master/BREAKING_CHANGES.md – Lalit Kushwah Aug 25 '19 at 16:22
  • This is the current way to way to call a methond in StencilJs . . . (async () => { await customElements.whenDefined('todo-list'); const todoListElement = document.querySelector('todo-list'); await todoListElement.showPrompt(); })(); – Jubish Kammily Oct 31 '21 at 09:10
  • I have Stencil 2.7.0 and still not working, it's PAINFUL. – LEMUEL ADANE Dec 10 '21 at 07:23
11

Just posting another answer because this has since changed, with Stencil One.

All @Method decorated methods are now immediately available on the component, but they are required to be async, so that you can immediately call them (and they resolve once the component is ready). The use of componentOnReady for this is now obsolete.

However, you should make sure that the component is already defined in the custom element registry, using the whenDefined method of the custom element registry.

<script>
(async () => {
  await customElements.whenDefined('my-name');

  // the component is registered now, so its methods are immediately available
  const myComp = document.querySelector('my-name');

  if (myComp) {
    await myComp.setName('Bob', 'Smith');
  }
})();
</script>
Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
0

Here you should not use @Method , it is not a best practice. We should always minimize the usage of @Method. This helps us to scale the app easily.

Instead pass data through @Prop and @Watch for it.

Ok , in your case , Please add async before the method name