javascriptweb-componentlit-elementlit

How to execute a script after the component load in Lit-Element


I'm trying to add a prefix to the phone number input after the component load, but I'm getting an error. In a normal web component, the connectedCallback() method would be enough but here it doesn't seem to work. How can I fix this?

The error I'm getting: Uncaught TypeError: Cannot read properties of null (reading 'getAttribute')

import { LitElement, html } from "https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js";
import "https://unpkg.com/intl-tel-input@17.0.19/build/js/intlTelInput.min.js";
import { formattedArray } from "./countries.js";

export class Form extends LitElement {
  static properties = {
    name: {},
    modalContent: {},
  };

  constructor() {
    super();
    this.countries = formattedArray;
  }

  render() {
    return html`
      <form class="flex flex-col gap-3" @submit=${this.handleSubmit}>
        <input type="text" class="form-control" placeholder="First name" name="first_name" />
        <input type="text" class="form-control" placeholder="Last name" name="last_name" />
        <input type="text" class="form-control" placeholder="Address" name="address" />
        <input type="text" class="form-control" placeholder="Zip Code" name="zip" />
        <input type="text" class="form-control" placeholder="City" name="city" />
        <select class="form-control" name="country">
          ${this.countries.map(country => html`<option value="${country}">${country}</option>`)}
        </select>
        <input type="tel" class="form-control" placeholder="Phone" name="phone" id="phone" />
        <input type="email" class="form-control" placeholder="Email" name="email" />
        <button type="submit" class="btn btn-primary">
          Continue
        </button>
      </form>
    `;
  }

  connectedCallback() {
    super.connectedCallback();
    // Initialize intlTelInput
    const input = document.querySelector("#phone");
    window.intlTelInput(input, {
      initialCountry: "auto",
      separateDialCode: true,
      utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js", // Add the correct path to utils.js
    });
  }

  handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.target);
    const formObject = Object.fromEntries(formData.entries());

    // Do something with the form data, for example, log it
    console.log("Form data:", formObject);

    this.dispatchEvent(new Event('submitted', {bubbles: true, composed: true}));
  }

  createRenderRoot() {
    return this;
  }
}

customElements.define("custom-form", Form);


Solution

  • As mentioned in the lit doc Use firstUpdatedto perform one-time work after the element's template has been created.

    firstUpdated() {
        // Initialize intlTelInput 
        const input = document.querySelector("#phone");
        window.intlTelInput(input, {
          initialCountry: "auto",
          separateDialCode: true,
          utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js", // Add the correct path to utils.js
        });
      } 
    

    Working Example