Integrate ES2015 Classes with jQuery

0

After a lot of reading I finally managed to make Babel work and thus transpile the scripts.

Before using das, let's call it ES2015 classes, after reading about best practices I had something like this:

( function( Navigation, window, document, $, undefined ) {

    Navigation.menu = function() {

        ( '#menu' ).on( 'click wheel', function( e ) {

            // Do something with DOM

        });
    }

    Navigation.menu();

}( window.Navigation = window.Navigation || {}, window, document, window.jQuery ) );

Then, slowly, I was trying to do the implementation with the ES2015:

class Navigation {

    constructor( data ) {

        this.data = data;

        this.init();
    }
}

class Menu extends Navigation {

    init() {

        $( '#menu' ).on( 'click wheel', function( e ) {

            // Do something with DOM
        });
    }
}

I created a base class with what is common to each type of navigation (menu, sidebar ...) thinking that as soon as the Menu object was instantiated the Navigation constructor > would call the init method, initializing the Event.

It works, but not as I imagined.

In Location in fact, but only to contextualize an abstract method), if I try to access the properties of Navigation :

console.log( this.data );

It works perfectly as expected but inside of jQuery.on () I get an undefined o.

I figured maybe the scope of Navigation.init() could be overwritten and debug only it and got the clicked node (an image).

And I wanted to know why, of course, but also how to fix this to integrate properly, if possible, but preferably without having to, for example, inject the scope this into this :

class Navigation {

    constructor( data ) {

        this.data = data;

        this.init( this );
    }
}

class Menu extends navigation {

    init( _this ) {

        // _this points to Navigation, inside or inside jQuery.on()
    }
}
    
asked by anonymous 10.01.2017 / 14:32

1 answer

2

This happens because of the way jQuery works with event callback, it causes this to be the element that fired the event.

As you are using Babel then it is very simple to solve this problem, you only use an Arrow Function , which differs from a function, anonymous or not, it does not change the context of this , it would look like this

init() {
    $( '#menu' ).on( 'click wheel', ( e ) => {
         // agora aqui o this vai continuar sendo a sua classe
    });
}

Note that all that has changed is the removal of the keyword function and the addition of the arrow => .

Babel will know how to convert this correctly, in the final javascript it should create a new temporary variable automatically

The detail that remains is that a common thing of jQuery is to use $(this) to manipulate the element that triggered the event, which will no longer work, but you can still pick up the element that triggered the event in this case by e.target or e.currentTarget , then you could also do something like $(e.target) to manipulate the element with jQuery.

In the case of e.target it may happen that it is not the same as this , this can happen when the event came from a child element from which you added the event handler, for example

<div id="menu">
    <div>
        teste
    </div>  
</div>

With this HTML if I add a handler for the click of the $("#menu") the e.target will return me the internal div , while the this would be the div external, in this case using e.currentTarget it would return the same as this .

The documentation does not say much about the difference between this and e.currentTarget , but researching it found explanations saying that in general they would be the same values unless $.proxy was used to change the context of the function.

I should also add that $.proxy is also an alternative to fix your problem, it would look like this:

init() {
    $( '#menu' ).on( 'click wheel', $.proxy(function( e ) {
         // agora aqui o this vai continuar sendo a sua classe
    }, this));
}

Basically, you pass the function and its this current, which represents the instance of your class, but still happens the same thing that would happen using an Arrow Function , as this was modified I do not know how to use $(this) , it would be necessary to use $(e.currentTarget) for example, so I find the first form simpler, getting the code cleaner.

In the last case, if you really want or for some reason need to use $(this) , then the alternative is to capture this in a local variable

init() {
    let _this = this; //ou var _this = this;
    $( '#menu' ).on( 'click wheel', function( e ) {
         // agora aqui você pode usar o _this para acessar sua classe
         // e ainda pode usar o $(this) para manipular o elemento
    });
}
    
10.01.2017 / 14:55