# lifecycle methods

[browser](https://lochiwei.gitbook.io/web/browser) ⟩ [web components](https://lochiwei.gitbook.io/web/component) ⟩ [implement](https://lochiwei.gitbook.io/web/component/implement) ⟩ [custom elements](https://lochiwei.gitbook.io/web/component/custom-element) ⟩ lifecycle methods

{% tabs %}
{% tab title="⭐️ 重點" %}
{% hint style="success" %}

* <mark style="color:yellow;">**constructor**</mark>()\
  an instance of custom element is **created** or **upgraded**.
* <mark style="color:yellow;">**connectedCallback**</mark>()\
  custom element is **appended** into/**moved** in a document.
* <mark style="color:orange;">**disconnectedCallback**</mark>()\
  custom element is **removed** from the document.
* <mark style="color:yellow;">**attributeChangedCallback**</mark>(<mark style="color:blue;">attrName</mark>, <mark style="color:blue;">oldVal</mark>, <mark style="color:blue;">newVal</mark>)\
  one of the custom element’s **attributes** is **added**/**removed**/**changed**. \
  observed attributes are specified with <mark style="color:blue;">`static get observedAttributes()`</mark>.
* <mark style="color:orange;">**adoptedCallback**</mark>()\
  custom element is **moved** to a **new document**.
  {% endhint %}
  {% endtab %}

{% tab title="📘 手冊" %}

* MDN ⟩ [Using the lifecycle callbacks](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks)
* Google ⟩ [Custom element reactions](https://developers.google.com/web/fundamentals/web-components/customelements#reactions) - a.k.a lifecycle callbacks
  {% endtab %}

{% tab title="📗 參考" %}

* [ ] JavaScript: The Definitive Guide (15.6 Web Components)
  {% endtab %}

{% tab title="💈範例" %}
:floppy\_disk: [web component life cycle](https://replit.com/@pegasusroe/web-component-life-cycle#script.js)

{% embed url="<https://codepen.io/lochiwei/pen/JjJXVrW>" %}

📁 HTML

```html
<div id="parent">
    <!-- web component -->
    <my-component text="my personal text"></my-component>
</div>

<button id="button" onclick="removeElement()">Remove Element</button>
```

📁 JS

```javascript
// ⭐️ 1. custom web component
class MyComponent extends HTMLElement {

    constructor(){ 
        
        // debug info
        console.log(`🐣 contructed ...`);

        // tell HTMLElement to initialize itself
        super();

        // variables
        const text = this.getAttribute('text') || 'Loren Ipsum';
        const size = randomInt(12, 50);     // random font size

        // create element
        const elem = document.createElement('template');
        elem.innerHTML = MyComponent.template(text, size);

        // add to UI
        this.appendChild(document.importNode(elem.content, true));
    }

    // HTML tempalte
    static template(text, size) { 
        return `
            <div style="font-size:${size}px">
                ${text} (font-size: ${size})
            </div>
        `;
    }

    /* -------- life-cycle triggers -------- */

    connectedCallback() { console.log(`🔌 connected ...`); } 
    disconnectedCallback() { console.log(`❌ disconnected ...`); }

    attributeChangedCallback(attrName, oldVal, newVal) { 
        console.log(`✏️ attribute "${attrName}" changed: ${oldVal} ➝ ${newVal}`); 
    }

    /*
        To get the attributeChangedCallback() method to work correctly, 
        we must add the static method observedAttributes() and 
        return the properties that we want to observe.
    */
    static get observedAttributes() { 
        return ['text']; 
    }

    /* --------- set/get `text` ---------- */

    set text(val) { this.setAttribute(`text`, val ?? ``); }
    get text() { return this.getAttribute('text'); }
} 

// ⭐️ 2. custom tag <my-component>
// ⭐️⭐️ custom element names must contain a "hyphen".
customElements.define('my-component', MyComponent);


/* -------- button -------- */

function removeElement() {

    const div = $('#parent');
    const element = $('my-component');
    const button = $('#button');

    div.removeChild(element);
    button.disabled = true;
}

/* -------- helpers -------- */

// $ ⭐️
function $(selector, parent = document){
  return parent.querySelector(selector);
}

// random integer between a and b
function randomInt(a, b){
    return Math.floor((Math.random() * (b - a + 1)) + a)
}
```

{% endtab %}
{% endtabs %}
