Life cycle callbacks | Web Components | Amit Padhiyar (Saatody)
You can define several different callbacks inside a custom element's class definition, which fire at different points in the element's lifecycle.
connectedCallback:
Invoked each time the custom element is appended into a document-connected element. This will happen each time the node is moved, and may happen before the element's contents have been fully parsed.
disconnectedCallback:
Invoked each time the custom element is disconnected from the document's DOM.
adoptedCallback:
Invoked each time the custom element is moved to a new document.
attributeChangedCallback:
Invoked each time one of the custom element's attributes is added, removed, or changed. Which attributes to notice change for is specified in a static get observedAttributes method
In Short...
connectedCallback: Invoked when the custom element is first connected to the document's DOM.
disconnectedCallback: Invoked when the custom element is disconnected from the document's DOM.
adoptedCallback: Invoked when the custom element is moved to a new document.
attributeChangedCallback: Invoked when one of the custom element's attributes is added, removed, or changed.
See below full example. The connectedCallback() method call when we define HTML custom element and also when we create new MyDemo class constructor using JavaScript. Every time the result will increment by 1.
This will effect like below output. Here 5 times disconnectionCallback() function calls when custom element remove from document.
Demo Of connectedCallback
Look at the below coding. Here, I take i variable and inside program it will increment by one. It means when connectedCallback() function the function will recognize and give output something like Connection: 1, Connection: 2.
# Main Coding
<script>
let i = 1;
class MyDemo extends HTMLElement{
connectedCallback(){
console.log("Connection: " + (i++));
}
}
window.customElements.define("my-demo", MyDemo, null);
</script>
# Full Example
# Connection Using HTML
# Connection Using JavaScript
<!DOCTYPE html>
<html>
<head></head>
<body>
<!-- Connection Using HTML -->
<my-demo></my-demo> <!-- 1 -->
<my-demo></my-demo> <!-- 2 -->
<script>
let i = 1;
class MyDemo extends HTMLElement{
connectedCallback(){
console.log("Connection: " + (i++));
}
}
window.customElements.define("my-demo", MyDemo, null);
</script>
<script>
<!-- Connection Using JavaScript -->
var myConnection3 = new MyDemo();
var myConnection4 = new MyDemo();
var myConnection5 = new MyDemo();
document.body.appendChild(myConnection3); <!-- 3 -->
document.body.appendChild(myConnection4); <!-- 4 -->
document.body.appendChild(myConnection5); <!-- 5 -->
</script>
</body>
</html>
Look at output. The Connection: 1 and Connection: 2 generated by HTML when Connection: 3, Connection: 4 and Connection: 5 generated by JavaScript Constructors.#Output
Connection: 1
Connection: 2
Connection: 3
Connection: 4
Connection: 5
Demo Of disconnectedCallback
Entire demo same as above example. But here we at last remove all elements from body using JavaScript. And we also defined disconnectedCallback() function.
# Full Program
# Disconnection Using JavaScript
<!DOCTYPE html>
<html>
<head></head>
<body>
<!-- Connection Using HTML -->
<my-demo></my-demo> <!-- 1 -->
<my-demo></my-demo> <!-- 2 -->
<script>
let i = 1;
let j = 1;
class MyDemo extends HTMLElement{
connectedCallback(){
console.log("Connection: " + (i++));
}
disconnectedCallback(){
console.log("Disconnection: " + (j++));
}
}
window.customElements.define("my-demo", MyDemo, null);
</script>
<script>
<!-- Connection Using JavaScript -->
var myConnection3 = new MyDemo();
var myConnection4 = new MyDemo();
var myConnection5 = new MyDemo();
document.body.appendChild(myConnection3); <!-- 3 -->
document.body.appendChild(myConnection4); <!-- 4 -->
document.body.appendChild(myConnection5); <!-- 5 -->
<!-- Disconnection Using JavaScript -->
document.getElementsByTagName("body")[0].innerHTML = "";
</script>
</body>
</html>
# Output
Connection: 1
Connection: 2
Connection: 3
Connection: 4
Connection: 5
Disconnection: 1
Disconnection: 2
Disconnection: 3
Disconnection: 4
Disconnection: 5
Demo Of adoptedCallback
An element can be adopted into a new document (i.e. someone called document.adoptNode(element)) and has a very specific use case. In general, this will only occur when dealing with <iframe/> elements where each iframe has its own DOM, but when it happens the adoptedCallback lifecycle hook is triggered. We can use it to interact with the owner document, the main document or other elements.
# Full Program
<!DOCTYPE html>
<html>
<head></head>
<body>
<iframe id='d1'></iframe>
<script>
let i = 1;
class MyDemo extends HTMLElement{
adoptedCallback(){
console.log("Elements Adopted By Iframe: " + (i++));
}
}
window.customElements.define("my-demo", MyDemo, null);
</script>
<script>
var demo = new MyDemo();
document.body.appendChild(demo);
var d1 = document.querySelector('#d1').contentDocument;
d1.body.appendChild(demo);
</script>
</body>
</html>
Note that the element is not destroyed and created again while adopting, so the constructor() method won’t be called.# Output
Elements Adopted By Iframe: 1
Demo Of attributeChangedCallback
This is most important callback function in entire life cycle. we can get and set value of custom HTML element's attributes. The attributeChangedCallback() callback is run whenever one of the element's attributes is changed in some way. First we are going to see syntax of attributeChangedCallback() function.
# Syntax
attributeChangedCallback(name, oldValue, newValue)
Here also use observedAttributes() to define attributes of custom elements. check out its syntax too.
# Syntax
static get observedAttributes() { return ['att1', 'att2']; }
We are going to see one simple example of the attributeChangedCallback() function and observedAttributes().
# Full Program
<!DOCTYPE html>
<html>
<head></head>
<body>
<my-text type='normal' message='This is normal text.'></my-text>
<my-text type='danger' message='This is danger text.'></my-text>
<my-text type='warning' message='This is warning text.'></my-text>
<my-text type='success' message='This is success text.' title='Hello Message'></my-text>
<script>
class MyText extends HTMLElement{
static get observedAttributes(){
return ['message','type'];
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(name + ": " + oldValue + " | " + newValue);
}
}
window.customElements.define("my-text", MyText, null);
</script>
</body>
</html>
In this example we defined two attributes which are message and it's type. And this is work and give output like the below output. But now the question is that if attribute is not defined in observedAttributes() and still attributeChangedCallback() function invoke? The answer in No. In Above example, At 4th <my-text> has one extra attribute which is title and its value is 'Hello Message' and also title attribute is not defined in observedAttributes(). So, attributeChangedCallback() function will not invoke. See in the below output.# Output
type: null | normal
message: null | This is normal text.
type: null | danger
message: null | This is danger text.
type: null | warning
message: null | This is warning text.
type: null | success
message: null | This is success text.
Now the same process we will do with JavaScript.# Full Program
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
class MyText extends HTMLElement{
static get observedAttributes(){
return ['message','type'];
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(name + ": " + oldValue + " | " + newValue);
}
}
window.customElements.define("my-text", MyText, null);
let MyText1 = document.createElement("my-text");
MyText1.type = "normal";
MyText1.message = "This is normal text.";
document.body.appendChild(MyText1);
let MyText2 = new MyText();
MyText2.type = "danger";
MyText2.message = "This is danger text.";
document.body.appendChild(MyText2);
let MyText3 = document.createElement("my-text");
MyText3.setAttribute("type","warning");
MyText3.setAttribute("message","This is warning text.");
document.body.appendChild(MyText3);
let MyText4 = new MyText();
MyText4.setAttribute("type","success");
MyText4.setAttribute("message","This is success text.");
document.body.appendChild(MyText4);
</script>
</body>
</html>
This how also we get output but here we get only two DOM output. Why this is happen? Let's see it in detail.# Output
type: null | warning
message: null | This is warning text.
type: null | success
message: null | This is success text.
The last two DOM creates attributes it self. So we can get output. But first two DOM can't give output because we not created set(){} and get(){} methods in DOM class. The last two uses setAttribute() and this method used for create attributes. while first two can't because, they have not uses setAttribute() function.# Full Program
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
class MyText extends HTMLElement{
static get observedAttributes(){
return ['message','type'];
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(name + ": " + oldValue + " | " + newValue);
}
set message(val){
this.setAttribute("message",val);
}
get message(){
return this.getAttribute("message");
}
set type(val){
this.setAttribute("type",val);
}
get type(){
return this.getAttribute("type");
}
}
window.customElements.define("my-text", MyText, null);
let MyText1 = document.createElement("my-text");
MyText1.type = "normal";
MyText1.message = "This is normal text.";
document.body.appendChild(MyText1);
let MyText2 = new MyText();
MyText2.type = "danger";
MyText2.message = "This is danger text.";
document.body.appendChild(MyText2);
let MyText3 = document.createElement("my-text");
MyText3.setAttribute("type","warning");
MyText3.setAttribute("message","This is warning text.");
document.body.appendChild(MyText3);
let MyText4 = new MyText();
MyText4.setAttribute("type","success");
MyText4.setAttribute("message","This is success text.");
document.body.appendChild(MyText4);
</script>
</body>
</html>
Here, We defined set and get methods. So, Now we can get output of first two constructors.# Output
type: null | normal
message: null | This is normal text.
type: null | danger
message: null | This is danger text.
type: null | warning
message: null | This is warning text.
type: null | success
message: null | This is success text.
The best practice is to define custom element's attributes with set and get methods. Why? See below little example.# Program
console.log("============================");
console.log(MyText1.type);
console.log(MyText2.type);
console.log(MyText3.type);
console.log(MyText4.type);
Because of set and get methods, You can set value or get value from attributes easily.# Output
normal
danger
warning
success
Now we try to add unknown attribute. So what happen? I don't but let me check! This test will happen with MyText1 and MyText3.# Program
let MyText1 = document.createElement("my-text");
MyText1.type = "normal";
MyText1.message = "This is normal text.";
MyText1.mytitle = "MyText1";
document.body.appendChild(MyText1);
let MyText3 = document.createElement("my-text");
MyText3.setAttribute("type","warning");
MyText3.setAttribute("message","This is warning text.");
MyText3.setAttribute("mytitle","MyText3");
document.body.appendChild(MyText3);
console.log("============================");
console.log(MyText1.mytitle);
console.log(MyText1.getAttribute("mytitle"));
console.log(MyText3.mytitle);
console.log(MyText3.getAttribute("mytitle"));
This way JavaScript not work properly.# Output
MyText1
null
undefined
MyText3
Comments
Post a Comment