<flag-icon> CE example
attributeChangedCallback runs early!
by dannye
HTML
<script>
class FlagIcon extends HTMLElement {
static observedAttributes = ["country"];
log(...args) {
document.body.appendChild(document.createElement("div"))
.innerHTML = `${this.id} - ${args.join` `}`;
}
attributeChangedCallback(name, oldValue, newValue) {
this.log("<b>attributeChangedCallback:</b>", `("${name}" , "${oldValue}", "${newValue}" )`);
if (this.isConnected) {
if (newValue == oldValue) this.log(`Don't call SETTER ${name} again!`);
else this[name] = newValue; // call SETTER
} else this.log("is not a DOM element yet!!!");
}
connectedCallback() {
this.log("<b>connectedCallback</b>, this.img:", this.img || "not defined");
if (!this.img) this.img = document.createElement("img");
this.append(this.img); // append isn't available in IE11
this.country = this.getAttribute("country") || "EmptyCountry";
}
get country() { // the Attribute is the truth, no need for private variables
return this.getAttribute("country");
}
set country(v) {
this.log("SETTER country:", v);
// Properties and Attributes are in sync,
// but setAttribute will trigger attributeChanged one more time!
this.setAttribute("country", v);
if (this.img) this.img.src = `//flagcdn.com/20x15/${v}.png`;
else this.log("can't set country", v);
}
}
customElements.define("flag-icon", FlagIcon);
document.body.onclick = () => {
flag1.country = "eu";
flag2.setAttribute("country", "nl");
document.body.append(flag1); // runs connectedCallback again!! Don't add another IMG!
}
</script>
<flag-icon id="flag1" country="in"></flag-icon><br>
<flag-icon id="flag2" country="us"></flag-icon><br>
JavaScript
/***************************************************************/
// chessboard Files and Ranks are drawn from A8 to H1
const FILES = "ABCDEFGH".split(""); // create an Array, saves us typing the whole Array
const RANKS = [8, 7, 6, 5, 4, 3, 2, 1];
// CSS colors for squares
const WHITE_SQUARE_COLOR = "#f0e9c5";
const BLACK_SQUARE_COLOR = "#b58863";
// Custom Element Name: <schaak-bord>
const CHESS_BOARD = "schaak-bord";
// Custom Element Name: <schaak-bord-square>
const CHESS_BOARD_SQUARE = CHESS_BOARD + "-square";
/***************************************************************/
// Object Oriented Programming: All our Custom Elements will
// extend from this BaseClass and inherit ALL its Methods and Properties
class GameBoardElement extends HTMLElement{
/*========================= CHESS BOARD setProperty =======*/
setProperty(name, value) {
this.style.setProperty("--" + name, value);
}
/*========================= CHESS BOARD setProperty =======*/
log(...args) {
console.log("%c <schaak-bord> ","background:purple;color:gold",...args);
}
}
/***************************************************************/
customElements.define(
CHESS_BOARD_SQUARE,
class extends GameBoardElement {
connectedCallback() {
this.innerHTML = this.id; // show square id A8 to H1
}
}
);
/***************************************************************/
customElements.define(
CHESS_BOARD,
class extends GameBoardElement {
/*========================= CHESS BOARD CONSTRUCTOR =======*/
constructor() {
// A shadowDOM allows multiple <schaak-bord> Elements in ONE page
super().attachShadow({
mode: "open", // define an editable shadowDOM for the custom element
});
/*--helper functions-------------------------------------*/
let addLayer = (id) => {
let layer = document.createElement("div");
...