<live-timer>
Exercise: <live-timer> element - JS.info
solution to the exercise
๐พ replit
// 1. define new element
class LiveTimer extends HTMLElement {
/* ---------- life cycle callbacks ---------- */
// triggers when element is added to page
// (or when HTML parser detects it)
connectedCallback() {
this.render();
// โญ๏ธ start timer
this.startTimer();
}
disconnectedCallback() {
// โญ๏ธ important to let the element be garbage-collected
this.cancelTimer();
}
/* ---------- helper methods ---------- */
render() {
// show a nicely formatted time.
// โญ๏ธ ๆณจๆ๏ผ้่ฃก่จญๅฎ็ๆฑ่ฅฟๅฑฌๆผ light DOMโ๏ธ
this.innerHTML = `
<time-formatted
year="numeric"
month="long"
day="numeric"
hour="numeric"
minute="numeric"
second="numeric"
time-zone-name="short">
</time-formatted>
`;
// โญ๏ธ reference to <time-formatted> child
this.timeChild = this.firstElementChild;
}
// update
update(){
this.date = new Date();
// โญ๏ธ update child
this.timeChild.attr('datetime', this.date);
// โญ๏ธ dispatch 'tick'
let tick = new CustomEvent('tick', {
detail: this.date
});
this.dispatchEvent(tick);
}
// start timer
startTimer(){
// โญ๏ธ ๆณจๆ๏ผไธ่ฆๅฏซๆใ setInterval(this.update, 1000) ใโ๏ธ
// ไธ็ถๆๅคฑๅป `this` contextโ๏ธ
this.timer = setInterval(() => this.update(), 1000);
}
// cancel timer
cancelTimer(){
// โญ๏ธ ๆณจๆ๏ผไธๆฏ this.timer = nullโ๏ธ
clearInterval(this.timer);
}
}
// 2. register new element
customElements.define("live-timer", LiveTimer);
// 1. define new element
class TimeFormatted extends HTMLElement {
/* ---------- life cycle callbacks ---------- */
constructor(){
super();
this.initialized = false;
}
// triggers when <time-formatted> element is added to page
// (or when HTML parser detects it)
connectedCallback() {
this.render();
this.initialized = true;
}
// 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();
// if(this.initialized) log(`${name} = ${newValue}`);
}
/* ---------- helper methods ---------- */
render() {
// let date = new Date(this.attr('datetime') || Date.now());
let date = new Date();
// 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);
const {log} = console;
// โญ๏ธ $()
function $(selector, parent = document){
return parent.querySelector(selector);
}
// โญ๏ธ 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;
};
// change attribute 'datetime' per second.
let timer1 = setInterval(
() => elem.attr('datetime', new Date()),
1000
);
// cancel above timer
function cancelTimer1(){
clearInterval(timer1);
}
<h3><time-formatted></h3>
<time-formatted
id="elem"
datetime="2019-12-01"
year="numeric"
month="long"
day="numeric"
hour="numeric"
minute="numeric"
second="numeric"
time-zone-name="short">
</time-formatted>
<h3><live-timer></h3>
<live-timer id="timer"></live-timer>
<br><br>
<button onclick="cancelTimer1()">cancel timer 1</button>
<button onclick="timer.cancelTimer()">cancel timer 2</button>
<script src="js/helper.js"></script>
<script src="js/TimeFormatted.js"></script>
<script src="js/LiveTimer.js"></script>
<script src="js/main.js"></script>
Last updated