I'm making a customised element that automatically localises it's visual text representation:
class LocalDate extends HTMLTimeElement {
// Specify observed attributes so that
// attributeChangedCallback will work
static get observedAttributes() {
return ["datetime"];
}
constructor() {
// Always call super first in constructor
const self = super();
this.formatter = new Intl.DateTimeFormat(navigator.languages, {
year: "numeric",
month: "short",
day: "numeric"
});
return self;
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "datetime") {
this.textContent = "";
const dateMiliseconds = Date.parse(newValue);
if (!Number.isNaN(dateMiliseconds)) {
const dateString = this.formatter.format(new Date(dateMiliseconds));
this.textContent = dateString;
}
}
}
}
customElements.define('local-date', LocalDate, {
extends: "time"
});
<time is="local-date" datetime="2022-01-13T07:13:00+10:00">13 Jan 2022 - Still here</time>
The kicker is when exactly the script tag is run - if it's run after the body is parsed, then it works as expected. Otherwise, instead of appearing as a date, the element displays the date string in addition to the text that was already in the element.
JsFiddle and StackOverflow both put the script tag at the bottom of the body, so the error can only be seen with a DataUrl:
data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%3E%0D%0A%3Chead%3E%0D%0A%3Cmeta%20charset%3D%22utf-8%22%2F%3E%0D%0A%3Ctitle%3ETime%20since%3C%2Ftitle%3E%0D%0A%3Cscript%3E%0D%0A%09class%20LocalDate%20extends%20HTMLTimeElement%20%7B%0D%0A%09%09%2F%2F%20Specify%20observed%20attributes%20so%20that%0D%0A%09%09%2F%2F%20attributeChangedCallback%20will%20work%0D%0A%09%09static%20get%20observedAttributes%28%29%20%7B%0D%0A%09%09%09return%20%5B%22datetime%22%5D%3B%0D%0A%09%09%7D%09%0D%0A%0D%0A%09%09constructor%28%29%20%7B%0D%0A%09%09%09%2F%2F%20Always%20call%20super%20first%20in%20constructor%0D%0A%09%09%09const%20self%20%3D%20super%28%29%3B%0D%0A%0D%0A%09%09%09this.formatter%20%3D%20new%20Intl.DateTimeFormat%28navigator.languages%2C%20%7B%20year%3A%20%22numeric%22%2C%20month%3A%20%22short%22%2C%20day%3A%20%22numeric%22%20%7D%29%3B%0D%0A%0D%0A%09%09%09return%20self%3B%0D%0A%09%09%7D%0D%0A%0D%0A%09%09attributeChangedCallback%28name%2C%20oldValue%2C%20newValue%29%20%7B%0D%0A%09%09%09if%20%28name%20%3D%3D%3D%20%22datetime%22%29%20%7B%0D%0A%09%09%09%09this.textContent%20%3D%20%22%22%3B%0D%0A%09%09%09%09const%20dateMiliseconds%20%3D%20Date.parse%28newValue%29%3B%0D%0A%09%09%09%09if%20%28%21Number.isNaN%28dateMiliseconds%29%29%20%7B%0D%0A%09%09%09%09%09const%20dateString%20%3D%20this.formatter.format%28new%20Date%28dateMiliseconds%29%29%3B%0D%0A%09%09%09%09%09%2F%2F%20Bizarrly%2C%20this%20doesn%27t%20seem%20to%20work%20without%20doing%20this%20in%20a%20timeout%3F%21%3F%21%0D%0A%09%09%09%09%09this.textContent%20%3D%20dateString%3B%0D%0A%09%09%09%09%7D%0D%0A%09%09%09%7D%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%09%0D%0A%09customElements.define%28%27local-date%27%2C%20LocalDate%2C%20%7B%20extends%3A%20%22time%22%20%7D%29%3B%0D%0A%3C%2Fscript%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%3E%0D%0A%3Cp%3ELast%20updated%20%3Ctime%20is%3D%22local-date%22%20datetime%3D%222022-01-13T07%3A13%3A00%2B10%3A00%22%3E13%20Jan%202022%20-%20Still%20here%3C%2Ftime%3E%3C%2Fp%3E%0D%0A%3C%2Fbody%3E
I've reproduced this in both Firefox and Chrome - any ideas what's going on here?