LWC: Difference between "window" and "this"
this
refers to the defaultclass
and not window.Container component (not owner) can add event listeners and access elements directly on
this
and nottemplate
. So, we should usethis.addEventListener
andthis.querySelector
Owner component has to add event-listeners and identification through
template
. So, we should usethis.template.addEventListener
andthis.template.querySelector
Please find below the example:
Consider 3 components Grandparent, parent, and child as below:
Grandparent.html:
<template>
<div>Grandparent:</div>
<c-parent>
<span slot='myslot'>
<c-child></c-child>
</span>
</c-parent>
</template>
Here, grandparent is the owner of
c-child
and parent component is only the container of child
Grandparent.js:
export default class Grandparent extends LightningElement {
constructor() {
super();
console.log('this => ', this);
this.addEventListener('myevent', this.myeventHandler);
this.template.addEventListener('myevent', this.myeventHandlerTemplate);
}
renderedCallback() {
console.log("Grandparent renderedCallback => ", this.querySelector('c-child'));
console.log("Grandparent renderedCallback template => ", this.template.querySelector('c-child'));
}
myeventHandler(event) {
console.log('Grand parent - myevent handled');
}
myeventHandlerTemplate(event) {
console.log('Grand parent template - myevent handled');
}
}
parent.html:
<template>
<div>
<slot name='myslot'></slot>
</div>
</template>
parent.js:
export default class Parent extends LightningElement {
constructor() {
super();
console.log('this => ', this);
this.addEventListener('myevent', this.myeventHandler);
this.template.addEventListener('myevent', this.myeventHandlerTemplate);
}
renderedCallback() {
console.log("parent renderedCallback => ", this.querySelector('c-child'));
console.log("parent renderedCallback template => ", this.template.querySelector('c-child'));
}
myeventHandler(event) {
console.log('parent - myevent handled');
}
myeventHandlerTemplate(event) {
console.log('parent template - myevent handled');
}
}
We are adding event-listeners and query-selectors on both direct
this
andtemplate
to check the functionality in both parent and grandparent.
child.js:
export default class Child extends LightningElement {
connectedCallback() {
this.dispatchEvent(new CustomEvent('myevent', { bubbles: true }));
}
}
bubbles:true
andcomposed:false
(default is false) will make the event bubble up until shadow boundary.
Below are the logs we get: (in order)
this => Grandparent {setAttribute: ƒ} this => Parent {setAttribute: ƒ} parent template - myevent handled parent - myevent handled Grand parent template - myevent handled parent renderedCallback => c-child parent renderedCallback template => null Grandparent renderedCallback => null Grandparent renderedCallback template => c-child
As you see,
this
has returned class instance.querySelector
for parent component worked only for directthis
and returnednull
on template.Also for event listener, container component -
parent
listened on directthis
. However, there appears to be some bug/unknown issue since container component is able to listen to the event ontemplate
.Only
template
binding worked in Grandparent.