Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the easiest way to pass an element as first argument to event handlers in JavaScript?

I know that having the value of this being changed to the element receiving the event in event handling functions is pretty useful. However, I'd like to make my functions always be called in my application context, and not in an element context. This way, I can use them as event handlers and in other ways such as in setTimeout calls.

So, code like this:

window.app = (function () {
    var that = {
        millerTime: function () {},
        changeEl: function (el) {
            el = el || this;
            // rest of code...
            that.millerTime();
        }
    };
    return that;
}());

could just be like this:

window.app = (function () {
    return {
        millerTime: function () {},
        changeEl: function (el) {
            // rest of code...
            this.millerTime();
        }
    };
}());

The first way just looks confusing to me. Is there a good easy way to pass the element receiving the event as the first argument (preferably a jQuery-wrapped element) to my event handling function and call within the context of app? Let's say I bind a bunch of event handlers using jQuery. I don't want to have to include anonymous functions all the time:

$('body').on('click', function (event) {
    app.changeEl.call(app, $(this), event);  // would be nice to get event too
});

I need a single function that will take care of this all for me. At this point I feel like there's no getting around passing an anonymous function, but I just want to see if someone might have a solution.

My attempt at it:

function overrideContext (event, fn) {
   if (!(this instanceof HTMLElement) ||
         typeof event === 'undefined'
   ) {
       return overrideContext;
   }

   // at this point we know jQuery called this function // ??
   var el = $(this);

   fn.call(app, el, event);
}

$('body').on('click', overrideContext(undefined, app.changeEl));

EDIT: Using Function.prototype.bind (which I am new to), I still can't get the element:

window.app = (function () {
    return {
         millerTime: function () {},
         changeEl: function (el) {
            // rest of code...
            console.log(this); // app
            this.millerTime();
         }
    };
}());

function overrideContext (evt, fn) {
    var el = $(this); // $(Window)
    console.log(arguments); // [undefined, app.changeEl, p.Event] 
    fn.call(app, el, event);
}

$('body').on('click', overrideContext.bind(null, undefined, app.changeEl));

Using $('body').on('click', overrideContext.bind(app.changeEl)); instead, this points to my app.changeEl function and my arguments length is 1 and contains only p.Event. I still can't get the element in either instance.

like image 339
danronmoon Avatar asked Oct 21 '22 21:10

danronmoon


1 Answers

You can use Function.prototype.bind.

$('body').on('click', overrideContext.bind(null, undefined, app.changeEl));

You could also pass in the actual element as the context for the method

$('body').on('click', overrideContext.bind(app.changeEl));
like image 144
jAndy Avatar answered Oct 25 '22 22:10

jAndy