1
votes

I'm trying to create custom component using Stencil with input. My intention is to make component with input. After change input value It should emit It to my Vue instance and console log this event (later it will update value in Vue instance). But after change input value in Stencil nothing happen.

Learning how Stencil components works I used:

https://medium.com/@cindyliuyn/create-a-stencil-form-input-component-for-angular-and-vue-js-22cb1c4fdec3

Trying to solve problem I tried also:

https://medium.com/sharenowtech/using-stenciljs-with-vue-a076244790e5

HTML and Vue code:

<!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="https://unpkg.com/vue"></script>
    <script type="module" src="/build/vox-wc-research.esm.js"></script>
    <script nomodule src="/build/vox-wc-research.js"></script>
  </head>
  <body>
    <div id="app">
      <test-component :placeholder="placeholder" :label="label" :value="value" @valueChange="e => onValueChange"></test-component>
      {{value}}
    </div>
  </body>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        label: 'Nazwa Użytkownika',
        value: '',
        placeholder: 'Wpisz nazwę użytkownika',
      },
      methods: {
        onValueChange(e) {
          console.log(e);
        },
      },
    });
  </script>
</html>

Stencil Component:

import { h, Component, Element, Event, EventEmitter, Prop /* PropDidChange */ } from '@stencil/core';
@Component({
  tag: 'test-component',
  styleUrl: 'test-component.css',
  //shadow: true,
})
export class FormInputBase {
  @Element() el: HTMLElement;
  @Prop() type: string = 'text';
  @Prop() label: string;
  @Prop() placeholder: string;
  @Prop({ mutable: true }) value: string;
  @Event() valueChange: EventEmitter;

  handleChange(event) {
    const val = event.target.value;
    console.log(val);
    this.value = val;
    this.valueChange.emit(val);
  }
  render() {
    return (
      <div>
        <label>
          {this.label}
          <div>
            <input placeholder={this.placeholder} value={this.value} onInput={event => this.handleChange(event)}></input>
            {this.value}
          </div>
        </label>
      </div>
    );
  }
}
1

1 Answers

2
votes

Vue doesn't support camel-case event names because all v-on: event listeners are converted to lower-case (see https://vuejs.org/v2/guide/components-custom-events.html#Event-Names).

However when you load your component(s), you can use the options of Stencil's defineCustomElements to "transform" all your event names:

import { applyPolyfills, defineCustomElements } from 'my-component/loader';

applyPolyFills().then(() => {
  defineCustomElements({
    ce: (eventName, opts) => new CustomEvent(eventName.toLowerCase(), opts)
  });
});

For a more full-blown example have a look at Ionic Framework's source:

https://github.com/ionic-team/ionic-framework/blob/b064fdebef14018b77242b791914d5bb10863d39/packages/vue/src/ionic-vue.ts