Lightning Web Components – How a Function Called from an Event Listener Can Refer to a Property of the LWC

javascriptlightning-web-components

In an LWC I need to perform some logic when a postMessage is received from an iframe. The logic needs to reference an api property of the LWC which is set by a parent component.
I want to supply a named function when I add the event listener so that the listener can later be removed.

Here's what I've tried:

import { LightningElement, api } from 'lwc';

export default class MikeComponentTwo extends LightningElement {

    @api
    someValue;

    someFunction(event) {
        alert(`Hello ${this.someValue} - ${this === window} - ${event.data}`);
    }

    connectedCallback() {
        window.addEventListener("message", this.someFunction);
    }
}

This produces

Hello undefined - true - {"token":"03ANYol..."}

So when someFunction runs, it doesn't know about someValue. I added in the check on this and can see that this === window.

How can I get around this?

Best Answer

In writing out what I tried, and trying other things, I got it working. It's likely a common pattern, so here's the working version.

When the listener calls the function, it sets this in the function to the object that fired that event, so window in this case. That's not helpful as window doesn't know about someValue.

Arrow functions to the rescue!

Remember that arrow functions do not have this. When you refer to this in an arrow function, "the lookup of this is made exactly the same way as a regular variable search: in the outer lexical environment."(1)

So re-writing the function as an arrow function means that it can now see someValue, and we have a listener, which can later be removed because it calls a named function, which calls that function, which refers to a property in the LWC.

import { LightningElement, api } from 'lwc';

export default class MikeComponentTwo extends LightningElement {

    @api
    someValue;

    someFunction = (event) => {
        alert(`Hello ${this.someValue} - ${this === window} - ${event.data}`);
    }

    connectedCallback() {
        window.addEventListener("message", this.someFunction);
    }
}

This produces

Hello Mike - false - {"token":"03ANYol..."}

If I add a console.log into someFunction:

    someFunction = (event) => {
        alert(`Hello ${this.someValue} - ${event.data}`);
        console.log(`this in someFunction: < ${this} >`);
    }

the console shows

this in someFunction: < SecureLightningElement [object d]{ key: {"namespace":"c"} } >

so we can see that this is the component itself.

The following resources helped with understanding this:

(1) https://javascript.info/arrow-functions

https://stackoverflow.com/questions/34913744/window-addeventlistenermessage-myfunctionevent-doesnt-work

https://www.sitepoint.com/javascript-this-event-handlers/

https://www.quirksmode.org/js/this.html

This answer was posted on https://salesforce.stackexchange.com by Mike Arthur. Any other sites displaying this content have not contributed to it in any way.

Related Topic