Javascript event handler with parameters

Go To StackoverFlow.com

61

I want to make an eventHandler that passes the event and some parameters. The problem is that the function doesn't get the element. Here is an example:

doClick = function(func){
    var elem = .. // the element where it is all about
    elem.onclick = function(e){
        func(e, elem);
    }
}
doClick(function(e, element){
    // do stuff with element and the event
});

The 'elem' must be defined outside of anonymous function. How can i get the passed element to use within the anonymous function? Is there a way to do this?

And what about addEventListener? I don't seem to be able to pass the event through an addEventListener at all do I ?

Update

I seemed to fix the problem with 'this'

doClick = function(func){
    var that = this;
    this.element.onclick = function(e){
        func(e, that);
    }
}

Where this contains this.element that i can access in the function.

The addEventListener

But i'm wondering about the addEventListener:

function doClick(elem, func){
    element.addEventListener('click', func(event, elem), false);
}
2012-04-03 19:32
by sebas2day
You have elem, elements, element involved in your question. Can you be less confusing - mihai 2012-04-03 19:44
I'm sorry, i was trying to make an example of my situation but this didn't went well, i updated the code - sebas2day 2012-04-03 19:54
Would you be looking for e.target / e.currentTarget - Rolf 2015-12-17 10:08
how to send a parameter if im using this : ok.addEventListener("click", this.changeText.bind(this) ) - Alberto Acuña 2016-02-26 10:41


70

I don't understand exactly what your code is trying to do, but you can make variables available in any event handler using the advantages of function closures:

function addClickHandler(elem, arg1, arg2) {
    elem.addEventListener('click', function(e) {
        // in the event handler function here, you can directly refer
        // to arg1 and arg2 from the parent function arguments
    }, false);
}

Depending upon your exact coding situation, you can pretty much always make some sort of closure preserve access to the variables for you.

From your comments, if what you're trying to accomplish is this:

element.addEventListener('click', func(event, this.elements[i]))

Then, you could do this with a self executing function (IIFE) that captures the arguments you want in a closure as it executes and returns the actual event handler function:

element.addEventListener('click', (function(passedInElement) {
    return function(e) {func(e, passedInElement); };
}) (this.elements[i]), false);

For more info on how an IIFE works, see these other references:

Javascript wrapping code inside anonymous function

Immediately-Invoked Function Expression (IIFE) In JavaScript - Passing jQuery

What are good use cases for JavaScript self executing anonymous functions?

This last version is perhaps easier to see what it's doing like this:

// return our event handler while capturing an argument in the closure
function handleEvent(passedInElement) {
    return function(e) {
        func(e, passedInElement); 
    };
}

element.addEventListener('click', handleEvent(this.elements[i]));

It is also possible to use .bind() to add arguments to a callback. Any arguments you pass to .bind() will be prepended to the arguments that the callback itself will have. So, you could do this:

elem.addEventListener('click', function(a1, a2, e) {
    // inside the event handler, you have access to both your arguments
    // and the event object that the event handler passes
}.bind(elem, arg1, arg2));
2012-04-03 19:41
by jfriend00
yes this almost what i'm trying to do, but what if the anonymous function get passed as parameter by the addClickHandler and you want to give this function some parameters with the event like: element.addEventListener('click', func(event, this.elements[i])) - sebas2day 2012-04-03 20:00
@sebas2day - You can't do element.addEventListener('click', func(event, this.elements[i])). Javascript just doesn't work that way. There are other ways around that, using closures, but you can't do it the way you wrote. addEventListener calls it's callback with exactly one argument (the event) and you can't change that in any way - jfriend00 2012-04-03 20:39
I added another example of doing this to the end of my answer - jfriend00 2012-04-03 20:47
Closure...best thing to happen since sliced bread - Skitterm 2014-11-26 19:04
@jfriend00 What you could do is use the bind method. function eventFunction (arg, evt) { console.log(arg[0],arg[1],arg[2]) console.log(evt) } var el = document.getElementById('elementID'); el.addEventListener('click', eventFunction.bind(el,[1,2,3]))

Note that the event argument is always last in the arguments for the function, and is not explicitly declared in the bind method - Knight Yoshi 2015-01-05 13:27

@jfriend00 I know it has been 3 years, but could you (or someone) explain the last line? "} (this.elements[i]) , false);" How does the parameter "this.elements[i]" gets passed? I know it works but I haven't found any information on why it works, not even how is this JavaScript capability of passing a value after the function definition called - Oscar Vasquez 2015-04-14 15:06
@Bosh19 - see what I've added to the end of my answer to explain the construct you asked about. It's an immediately invoked function expression (IIFE) which is essentially an anonymously declared function that is immediately executed. It's a shortcut for defining a function and then calling it - useful when you want the body inline and it will not be called anywhere else so it doesn't need a name - jfriend00 2015-04-14 23:31
@jfriend00 Thank you for the detailed explanation. The answer is a lot clearer now - Oscar Vasquez 2015-06-01 17:00


9

Something you can try is using the bind method, I think this achieves what you were asking for. If nothing else, it's still very useful.

function doClick(elem, func) {
  var diffElem = document.getElementById('some_element'); //could be the same or different element than the element in the doClick argument
  diffElem.addEventListener('click', func.bind(diffElem, elem))
}

function clickEvent(elem, evt) {
  console.log(this);
  console.log(elem); 
  // 'this' and elem can be the same thing if the first parameter 
  // of the bind method is the element the event is being attached to from the argument passed to doClick
  console.log(evt);
}

var elem = document.getElementById('elem_to_do_stuff_with');
doClick(elem, clickEvent);
2015-01-05 13:54
by Knight Yoshi


9

It is an old question but a common one. So let me add this one here.

With ES2015 syntax you can achieve it more succinct way:

function event_handler(event, arg) {
  console.log(event, arg);
}

element.addEventListener('click', (event) => event_handler(event, 'Here comes the argument'));
2018-02-27 18:40
by SnnSnn
This seems like a reasonable solution but what about when you have to remove the same event listener - Dushyant Sabharwal 2018-04-25 20:43
You can assign the event function to a variable and use that variable to add or remove. var e = (event) => event_handler(event, 'Here comes the argument'); element.addEventListener('click', e); element.removeEventListener('click', e);SnnSnn 2018-04-27 10:48


2

Given the update to the original question, it seems like there is trouble with the context ("this") while passing event handlers. The basics are explained e.g. here http://www.w3schools.com/js/js_function_invocation.asp

A simple working version of your example could read

var doClick = function(event, additionalParameter){
    // do stuff with event and this being the triggering event and caller
}

element.addEventListener('click', function(event)
{
  var additionalParameter = ...;
  doClick.call(this, event, additionalParameter );
}, false);

See also Javascript call() & apply() vs bind()?

2016-06-16 08:48
by Echsecutor


0

this inside of doThings is the window object. Try this instead:

var doThings = function (element) {
    var eventHandler = function(ev, func){
        if (element[ev] == undefined) {
            return;
        }

        element[ev] = function(e){
            func(e, element);
        }
    };

    return {
        eventHandler: eventHandler
    };
};
2012-04-03 19:50
by jbabey


0

Short answer:

x.addEventListener("click", function(e){myfunction(e, param1, param2)});

... 

function myfunction(e, param1, param1) {
    ... 
} 
2018-12-31 09:57
by user3093134


-2

let obj = MyObject();

elem.someEvent( function(){ obj.func(param) } );

//calls the MyObject.func, passing the param.
How does this solve the OP's problem - RamenChef 2016-11-16 13:54
param can be also a callback function (in the -say- global context) and so can be easily called-back, whith the requested parameters - Δημήτρης Βουζουναράς 2016-11-16 17:18