Integrate ES2015 Classes with jQuery

Asked

Viewed 38 times

0

After much reading I finally managed to do the Babel work and thus transcompile the scripts.

Before using das, let’s call 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 ) );

So, little by little, I was trying to do the implementation with 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 so Object Menu the manufacturer of Navigation would call the method init, Initiating the Event.

Works, but not as I imagined.

Within Navigation.init() (Location actually, 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 within jQuery.on() I get one Undefined o. The

I imagined that, perhaps, the scope of thiscould be overwritten and I debug only it and got the node clicked (an image).

And I wanted to know why, of course, but also how to fix it to integrate properly, if possible, but preferably without having to, for example, inject the scope this in Navigation.init():

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()
    }
}

1 answer

2


This happens by the way jQuery works with event callbacks, it makes the this be the element that triggered the event.

Since you are using Babel so it is very simple to solve this problem, just use one Arrow Function, that different from a function, anonymous or not, it does not change the context of the this, would look like this

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

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

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

The detail that is there 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 catch 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 may not happen to be the same element of this, this can happen when the event came from a child element from which you added Event Handler, for example

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

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

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

I might add that the $.proxy also is an alternative to fix your problem, would so:

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 your this current, which represents the instance of your class, but still happens the same thing that would happen using a Arrow Function, like the this modified has no way to use the $(this), it would be necessary to use $(e.currentTarget) for example, so I find the first way simpler, getting the cleaner code.

In the latter case, if you really want or for some reason need to use $(this), then the alternative is to capture the 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
    });
}
  • And start using $( e.target ) instead of $( this ) is safe, no compatibility problems?

  • @user5613506 I would say that in most cases yes, but the documentation mentions that there are cases where the this and the e.target may not be the same element in case the event spread of some child element, but looking at the documentation it seems possible to use also the e.currentTarget, I will include some more information in the reply

Browser other questions tagged

You are not signed in. Login or sign up in order to post.