javascriptecmascript-6web-componentlit-html

How to render the value in the form using web components or lit-html?


I am using lit-html library to render the data into the form.

The program should auto fill the product name upon inputting the product number. I have written the code but I am unable to auto fill the product name field. For the product name, I have used static dummy data within my JavaScript code.

Is there a way to do this using only web components or using library 'lit-html'?

Below you can find my code

import {html, render} from 'lit-html'

class MyApp extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({mode: 'open'});
        const forms = () => {
            const productNum = new Array();
            const productName = new Array();

            productNum[0] = 123;
            productName[0] = 'Paper';
            productNum [1] = 500;
            productName[1] = 'Laptop';

            function details(products) {
                if (products > 50) {
                    for (let i = 0; i < productNum.length; i++) {
                        if (products == productNum[i]) {
                            this.info.product.value = productName[i]
                        } else {
                            this.info.product.value = ''
                        }
                    }
                }
            }

            return html` <form name = 'info'>
                  <input type="text" name="product" onkeyup="${details(parseInt(this.value, 10))}" maxlength=3>ProductNum
                  <input type="text" name="productName" onkeyup="">ProductName
                </form>`

        }
        const template = html`
            ${forms()}`

        render(template, this.shadowRoot)
    }

}


window.customElements.define('my-app', MyApp)

Solution

  • Objective: (auto)Fill related Form fields with (product) data

    One (native) component way is to let the FORM handle the querying for product data
    Communicate productinfo with Events

    That way there is no dependency between components (other than an EventName),
    and you can have as many related inputs as you need.

    Relevant Custom Element code:

    <my-form>
      <my-input name="productkey"></my-input>
      <my-input name="productname"></my-input>
    </my-form>
    
    customElements.define("my-form", class extends HTMLElement {
      constructor() {
        super();
        let products = productDatabaseMap();
        this.addEventListener("getProduct", evt => {
          let detail={
            product: products[evt.detail.value],
            input: evt.target // input that requested product details
          };
          dispatchEvent(this, "setProduct", detail);
        });
      }
    })
    customElements.define("my-input", class extends HTMLElement {
      constructor() {
        super();
        let input = this.appendChild(document.createElement('input'));
        let name = input.placeholder = this.getAttribute('name');
        this.onkeyup = evt => dispatchEvent(input, "getProduct", evt.target);
        this.closest("my-form").addEventListener("setProduct", evt => {
          let product = evt.detail.product;
          if (product instanceof Product) input.value = product[name];
          else if (evt.detail.input !== input) input.value = '';
        });
    
      }
    })
    

    Working JSFiddle: https://jsfiddle.net/WebComponents/L2dcruoh/

    If you wrap <my-input> in a shadowRoot you need more boilerplate code and be aware event.detail then needs composed:true to make it cross shadow boundaries. And event.target will reference the (last) component it came from... not the input field that triggered that event