3

I try to create a custom textbox via Web Components

'use strict';

class TextBox extends HTMLElement {

  constructor() {
    super();

    var shadow = this.attachShadow({ mode: 'open' });

    let textbox = document.createElement("input");
    shadow.appendChild(textbox);
    textbox.addEventListener("change", this.validate);


    textbox.value ="Init";

  }

   validate(event) {

    console.log("input can be validated");
  }

  get value() {
    console.log("get");
    let textbox = this.shadowRoot.querySelector("input");
    return textbox.value;

  }

  set value(newValue) {
    console.log("set");
    let textbox = this.shadowRoot.querySelector("input");
    textbox.value = newValue;
  }

}
customElements.define('test-textbox',TextBox);

Later I would like to embedd the custom input in a template and change its values before adding it:

 let control= document.getElementById("control");
 let clone = control.content.cloneNode(true);
 clone.children[0].value = "tb value has been changed before adding";
 document.getElementById("app").appendChild(clone);

But If do this in my code the value of the input stays on "Init", but the value of my custom control will have the property "tb value has been changed before adding".

Would it be better to extend from HTMLInput? The set routine also only fires once.

J. Doe
  • 303
  • 3
  • 11

2 Answers2

0

Value is an attribute of input not a property. To set an attribute of an HTML Element you have to use textbox.setAttribute('value', myNewValue)

Pascal L.
  • 1,261
  • 9
  • 21
0

You shouldn't need to extend HTMLInput. Here's how I would do it. I added passed all properties attached to <text-box /> to its internal input element, but it's not necessary unless you're trying to mimic an input element more closely.

I'm hoping that extending specific elements like HTMLInput won't be a problem soon, but I tend to avoid them because there are some issues with them at the moment.

const css = `
  <style>
    :host([hidden]) { display: none; }
    :host {
      display: block;
    }
    input {
      background-color: #f5f5f5;
      border: 1px solid transparent;
      border-radius: 4px;
      padding: 1em;
      font-size: 16px;
      width: 400px;
    }
    input:focus {
      background-color: #fff;
      border: 1px solid #dadce0;
      outline: 0;
    }
  </style>
`

const html = `<input type='text' value='Init' />`

class TextBox extends HTMLElement {
  static get observedAttributes () {
    return ['value']
  }

  constructor () {
    super()

    this.attachShadow({mode: 'open'})
    this.shadowRoot.appendChild(template.content.cloneNode(true))

    // Cache the value of the inputNode
    this.inputNode = this.shadowRoot.querySelector('input')

    this.inputNode.value = 'Something else'

    // Add all properties on text-box to input
    for (let i = 0; i < this.attributes.length; i++) {
      this.inputNode.setAttribute(
        this.attributes[i].nodeName,
        this.attributes[i].nodeValue
      )
    }
  }

  validate (event) {
    console.log('input can be validated')
  }

  get value () {
    return this.inputNode.value
  }

  set value (newValue) {
    this.inputNode.value = newValue
  }

  connectedCallback () {
    this.inputNode.addEventListener('change', this.validate)
  }

  disconnectedCallback () {
    this.inputNode.removeEventListener('change', this.validate)
  }

  attributeChangedCallback (name, oldValue, newValue) {
    if (name === 'value') {
      this.inputNode.value = newValue
    }
  }
}

const template = document.createElement('template')
template.innerHTML = `${css}${html}`

window.customElements.define('text-box', TextBox)
Christopher Bradshaw
  • 2,615
  • 4
  • 24
  • 38