<time-formatted>

Custom Element Upgrade

The process of calling customElements.define() and endowing an existing element with a class definition is called "element upgrades". ๐Ÿ“˜ Google โŸฉ Element Upgrades

If browser encounters<time-formatted>elements beforecustomElements.define, the element is yet unknown, just like any non-standard tag.

When customElement.define is called, they are โ€œupgradedโ€: a new instance of TimeFormatted is created for each, and connectedCallback is called.

code

// โญ๏ธ get/set attribute
//    get: elem.attr(name)
//    set: elem.attr(name, value)
Element.prototype.attr = function(name, value=undefined){
    if(value !== undefined){ this.setAttribute(name, value) };
    return this.getAttribute(name) || undefined;
};

// 1. define new element
class TimeFormatted extends HTMLElement {

    /* ---------- life cycle callbacks ---------- */

    // triggers when <time-formatted> element is added to page
    // (or when HTML parser detects it)
    connectedCallback() {
        this.render();
    }

    // observed attributes
    static get observedAttributes() { // (3)
        return [
            'datetime', 'year', 'month', 'day', 
            'hour', 'minute', 'second', 'time-zone-name'
        ];
    }

    attributeChangedCallback(name, oldValue, newValue) { 
        // re-render when attributes changed
        this.render();
    }

  /* ---------- helper methods ---------- */
  
    render() {

        let date = new Date(this.attr('datetime') || Date.now());

        // built-in Intl.DateTimeFormat formatter
        let formatter = new Intl.DateTimeFormat("default", {
        year  : this.attr('year'),
        month : this.attr('month'),
        day   : this.attr('day'),
        hour  : this.attr('hour'),
        minute: this.attr('minute'),
        second: this.attr('second'),
        timeZoneName: this.attr('time-zone-name'),
        });

        // show a nicely formatted time.
        // โญ๏ธ ๆณจๆ„๏ผš้€™่ฃก่จญๅฎš็š„ๆฑ่ฅฟๅฑฌๆ–ผ light DOMโ—๏ธ
        this.innerHTML = formatter.format(date);
    }
}

// 2. register new element
customElements.define("time-formatted", TimeFormatted);

// change attribute 'datetime' per second.
setInterval(
    () => elem.attr('datetime', new Date()), 
    1000
);

Last updated