Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How adding event handler inside a class with a class-method as the callback?

How do I add an event handler inside a class with a class-method as the callback?

<div id="test">move over here</div>
<script>
    oClass = new CClass();
    function CClass()
    {
        this.m_s = "hello :-/";
        this.OnEvent = OnEvent;
        with(this)
        {
            var r = document.getElementById("test");
            r.addEventListener('mouseover', this.OnEvent);  // this does NOT work :-/
        }
      
        function OnEvent()
        {
            alert(this);    // this will be the HTML div-element
            alert(this.m_s);    // will be undefined :-()
        }
    }
</script>

Yes I know some quirks to make it work but what would be the intended way when these event handlers were introduced ??? I again have the bitter feeling, that no-one truly lives OOP :-(

Here for you to play: https://jsfiddle.net/sepfsvyo/1/

like image 276
born loser Avatar asked May 01 '17 22:05

born loser


People also ask

Is an event handler a callback?

An event handler is a type of callback. It's called whenever an event occurs. The term is usually used in terms of user interfaces where events are things like moving the mouse, clicking something and so on.

How do you bind an event handler to a class method in typescript?

In ES5, we can very easy bind a event to DOM using the native way: document. addEventListener() , or a jQuery way, $(element). bind() , $(element).

Can you add event listeners to classes?

To add an event listener to all elements with class: Use the document. querySelectorAll() method to select the elements by class. Use the forEach() method to iterate over the collection of elements.


2 Answers

The this inside the event listener callback will be the element that fired the event. If you want the this to be the instance of your class, then either:

Bind the function to the class instance:

Using Function.prototype.bind, will create a new function that its this value will always be what you specify it to be (the class instance):

r.addEventListener('mouseover', this.OnEvent.bind(this));
//                                          ^^^^^^^^^^^

Wrap the function inside an anonymous function:

var that = this;
r.addEventListener('mouseover', function(ev) { that.OnEvent(ev); });
//                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

or use an arrow function (so no need for that):

r.addEventListener('mouseover', ev => this.OnEvent(ev));
//                              ^^^^^^^^^^^^^^^^^^^^^^

Note: As mentioned in a comment bellow, both of the above methods pass a different function to addEventListener (the one with bind create a new function, and the anounimous function is obviously !== this.OnEvent). If you are going to remove the event listener later, you'll have to store a reference to the function:

var reference;
r.addEventListener('mouseover', reference = this.OnEvent.bind(this));
//                              ^^^^^^^^^^^^

or:

var reference;
var that = this;
r.addEventListener('mouseover', reference = function(ev) { that.OnEvent(ev); });
//                              ^^^^^^^^^^^^

then you can remove the event listener like:

r.removeEventListener('mouseover', reference);
like image 139
ibrahim mahrir Avatar answered Oct 23 '22 09:10

ibrahim mahrir


You can actually return the object as an EventListener callback, this way JS will search for an handleEvent method in the class and execute accordingly :

var myInstance = new myClass;
myInstance.addEventListener("mousedown",myInstance);

//  To remove the event you can follow the same pattern
myInstance.removeEventListener("mousedown",myInstance);

You have to construct your class this way :

class myClass {
   
    constructor(){
        //  Whatever this is supposed to do.
        //  You can also add events listener within the class this way :
        this.addEventListener("mousedown",this);
    }
    
    mouseDownEvent(e)(){
        //  Some action related to the mouse down event (e)
        console.log(e.target);
    }
    mouseMoveEvent(e)(){
        //  Some action related to the mouse move event (e)
    }
    mouseUpEvent(e)(){
        // Some action related to the mouse up event (e)
    }

    handleEvent(e) {
        switch(e.type) {
            case "mousedown":
                this.mouseDownEvent(e);
            break;
            case "mousemove":
                this.mouseMoveEvent(e);
            break;
            case "mouseup":
                this.mouseUpEvent(e);
            break;
        }
    }
}

Sources :

https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38

https://www.thecssninja.com/javascript/handleevent

https://metafizzy.co/blog/this-in-event-listeners/

I find this method clearer, also while declaring events inside the class this is pretty explicit. Hope I helped someone.

like image 37
Chalibou Avatar answered Oct 23 '22 09:10

Chalibou