2

For an element in my LWC, within mousedown handler, I want to add a mousemove handler and also call a function. The mousemove handler will also call the same function.

At the moment I'm trying to call 'myTestFunction' - the mousedown handler adds the mousemove handler, and then successfully calls 'myTestFunction'. But when the mousemove handler gets called an error is thrown -

 [this.myTestFunction is not a function]
Function: handleMouseMove

Why can't my mousemove handler recognise myTestFunction?

Code:

.js

import { LightningElement, track } from 'lwc';

export default class App extends LightningElement {
    myTestFunction(e) {
        console.log('test');
        console.log(e);
    }
    handleMouseDown(e) {
        e.target.addEventListener("mousemove", 
            this.handleMouseMove
        );

        this.myTestFunction(e);
    }

    handleMouseMove(e) {
        this.myTestFunction(e);
    }

    handleMouseUp(e) {
        e.target.removeEventListener("mousemove",
            this.handleMouseMove
        )
    }
    
}

.html

<template>
    <div onmousedown={handleMouseDown} onmouseup={handleMouseUp}></div>
</template>
7

Explicit use of addEventListener against some arbitrary element in the DOM requires you to explicitly bind the "this". To handle this you need to:

    _boundHandler;

    handleMouseDown(e) {
        if (!this._boundHandler) {
            this._boundHandler = this.handleMouseMove.bind(this);

            e.target.addEventListener("mousemove", 
                this._boundHandler);
        }

        this.myTestFunction(e);
    }

    handleMouseUp(e) {
        if (this._boundHandler) {
            e.target.removeEventListener("mousemove",
                this._boundHandler);
            this._boundHandler = undefined;
        }
    }

Note that you need to retain the specific bound handler otherwise the removal of the event listener won't work (different calls to bind generate different versions of the function) and you get "memory leaks".

Also note that explicit use of adding and removing event listeners anywhere except to the template OR the component itself is against LWC recommended practice.

This may suggest you should instead allow the event to bubble up to the component and use component-level handling, perhaps like:

   handleMouseDown(e) {
        this.addEventListener("mousemove", 
            this.handleMouseMove);

        this.myTestFunction(e);
    }

    handleMouseUp(e) {
        this.removeEventListener("mousemove", this.handleMouseMove);
    }

See the documentation for further details.

5
  • Salesforce explicitly states not to use bind as it would lead to memory leakage. Check out the important note here: developer.salesforce.com/docs/component-library/documentation/…
    – arut
    Aug 17 '20 at 10:46
  • 3
    That is EXACTLY why I have the _boundHandler variable. I explain this here. I will add that link to the answer. Also note the final point I made...
    – Phil W
    Aug 17 '20 at 10:59
  • Thanks for updating your answer with more details. Nice solution to prevent the memory leakage while using bind method. However, I'm not really clear on your last point because this user is trying to add event handlers to the element within the component scope.
    – arut
    Aug 17 '20 at 11:41
  • 2
    Since the OP was trying to add it to a generic DOM element I covered that with the first part. If they can allow the event to bubble up and catch it on the component level itself this would be far better, hence the second part.
    – Phil W
    Aug 17 '20 at 11:44
  • Ah, that's right. I guess I should have read your last point one more time before I posted the comment.
    – arut
    Aug 17 '20 at 11:53
1

A simpler way to solve this problem might be to rewrite 'handleMouseMove' as an arrow function which will then be able to see this.myTestFunction.

handleMouseMove = (e) => {
        this.myTestFunction(e);
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.