How to pass event and other arguments to click handler - javascript

Hey I have a build a canvas using easelJS.
In my canvas, I have points which a click handler is define for them using the following syntax:
p.on("click", handleMouseClickEvent);
Now I want to pass arguments to the handler handleMouseClickEvent , I know that I get the event object for free without passing it, but when I try to pass one argument, lets say I write:
p.on("click", handleMouseClickEvent(arg1));
Then the event object is undefined and not accessible at all.
How can I pass the event object and many more arguments using the above syntax.
p.on("click", handleMouseClickEvent(arg1,arg2,...,argN));

When using jQuery, Ravi's answer is perhaps the best way.
I'll try to provide another perspective to solve your question.
By using
p.on("click", handleMouseClickEvent(arg1));
you're not passing the function as event handler, you're executing it and passing its return value as event handler.
That perhaps already pointed you to the answer, right?
Try to define your event handler like this:
function handleMouseClickEvent(arg1)) {
return function reallyHandleMouseClickEvent(event) {
// all variables available here: arg1, event
}
}
Of course, you can add as many argN parameters as you want.

Since you're not calling the handler function yourself (the browser is doing it for you), you don't get to specify further arguments to the handler. All you'll get is the event object.
However, because of how JavaScript's variable scoping works, you don't have to. Functions have access to variables outside themselves, so you can simply access variables without passing them in explicitly:
var foo = "bar";
var handleMouseClickEvent = function(e) {
console.log(e.type); // 'click'
console.log(foo); // 'bar'
};
p.on("click", handleMouseClickEvent);

You need to define your event handler, try this:
function handleMouseClickEvent(arg1)) {
return function doSomething(event) {
//logic here
}
}

you can try this:
p.on("click", null, {arg1: "abc", arg2: "xyz"},handleMouseClickEvent);
//And in your function, you can get the event data like this
function handleMouseClickEvent()
{
alert(event.data.arg1);
alert(event.data.arg2);
}
According to official documenatation, on takes arguments like this:
.on( events [, selector ] [, data ], handler )
events Type: String
One or more space-separated event types and optional namespaces, such as
"click" or "keydown.myPlugin".
selector Type: String
A selector string to filter the descendants of the selected elements that > > > trigger the event. If the selector is null or omitted, the event is always
triggered when it reaches the selected element.
data Type: Anything
Data to be passed to the handler in event.data when an event is triggered.
handler Type: Function( Event eventObject [, Anything
extraParameter ] [, ... ] )
A function to execute when the event is
triggered. The value false is also allowed as a shorthand for a
function that simply does return false.
For more information, see JQuery Documentation of on() event Handler

Just to throw a more context-specific answer into the mix. I believe this question was asked in reference to this codepen: http://codepen.io/Barak/pen/AXZxKN
From an architecture standpoint, injecting parameters into handlers is a workaround you don't need. Instead, use the event target to access what was clicked/interacted with, and determine the values you need.
For your example, you are looking for the original data properties used to plot the points in your graph. You can either inject those properties onto the display object, inject a reference to the original data object, or create a look-up table to associate the display object with its related data point.
for (...) {
var point = data[i];
var dot = new createjs.Shape();
dot.x = point.x * GRAPH_WIDTH;
// Inject property or reference
dot.point = point;
// Create lookup
lookupTable[i] = dot;
}
Then when you click the object, look up the data.
dot.on("click", function(event) {
var dot = event.target;
// Use reference
var point = dot.point;
// Or use lookup
var index = lookup.indexOf(dot);
//...do stuff with it
}
There are lots of other ways to create this relationship, these are just some suggestions. Creating wrapper functions will work, but IMHO it is not a great approach for the long term or for a larger application. You can totally continue to use your approach, as it appears to be working for you -- but I wanted to offer some food for thought.
Cheers.

This should handle it. You can add more arguments.
(function(arg1, arg2) {
p.on("click", function(event) { handleMouseClickEvent(event, arg1, arg2) })
})(arg1, arg2);

The arguments can be bound to a handler function with Function.prototype.bind
p.on("click", handleEventWithArg.bind(this,arg1));
function handleEventWithArg(arg1, event) {
console.log(arg1);
console.log(event);
});
The .bind method returns a new functon that the browser can invoke with the event object.

Related

How do you remove an event listener that uses an anonymous function for passing parameters?

Apologies in advance as I have done some searching and this appears to be a fairly common question, but none of the answers I have found quite meet my needs. The closest I was able to find was How do I add and remove an event listener using a function with parameters?, but the answer there involves JQuery and I am trying to find a way to do this in just JS.
I am using anonymous functions to pass parameters through an event trigger which I believe is the correct way to do so. If temp is defined by some calculations based on the state at the time the event is added, I want to add the listener as follows:
item.addEventListener("click", function(){myOnClickFunction(temp)});
However, I want to be able to remove the event dynamically if certain conditions are met.
item.removeEventListener("click", function(){myOnClickFunction(temp)});
This does not work as the inline function is anonymous and cannot be referenced for matching up the event listener (plus temp is likely different anyway). Since temp is calculated at the time of the trigger, I cannot store a reference outside of the anonymous function with something like this:
var listener = function() {
var temp = calculate(arg1, arg2, event);
myFunction(temp);
};
window.addEventListener('click', listener, false);
so that I can later call:
window.removeEventListener('click', listener, false);
myOnClickEvent(temp){
//My code and calculations here
document.removeEventListener("keypress", arguments.callee);
}
is also not working, although I'm less confident as to how that method is supposed to work.
How can I remove this function dynamically? In some cases, I might be able to refactor my code so that all variables that need to be passed are stored globally and rewritten constantly, but that sounds like messy code. Plus, in some cases the trigger event is one of the arguments that needs to be passed so I don't think I could make that happen. Any ideas?
You can create an object, whose properties are the temp values, and whose values are myOnClickFunction bound to that temp. For example:
const boundFns = {};
// acquire temp somehow
const boundFn = () => myOnClickFunction(temp);
boundFns[temp] = boundFn;
item.addEventListener("click", boundFn);
Then, when you need to remove the listener, retrieve the appropriate bound function:
item.removeEventListener("click", boundFns[temp]);
If a temp may be used more than once, check if it exists in boundFns first:
const boundFns = {};
// acquire temp somehow
if (!boundFns[temp]) {
boundFns[temp] = () => myOnClickFunction(temp);
}
const boundFn = boundFns[temp];
boundFns[temp] = boundFn;
item.addEventListener("click", boundFn);
If temp cannot be be used reliably as a unique object key (for example, if it's an HTMLElement), you can use a Map instead, which is like an object, but whose keys can be anything, not just strings:
const boundFns = new Map();
boundFns.set(temp, boundFn);
// ...
item.removeEventListener("click", boundFns.get(temp));

Is there a way to pass multiple arguments to a event function in backbone js?

I have event and function pairs like this ..
events : {
'click #category' : 'categoryList',
}
My function needs argument result set to be passed in .
categoryList: function(rs){
this.modelmaker(rs);
var array = JSON.parse('['+ arraymodels +']');
makeList(array,'ProdCat',function(html){$("#listofstuffs").append(html);});
alert(collection.length);
},
if i try to give categorylist(rs) as function value in event function pair it says function is not defined .!
there should be some questions already explaining about this kind of trivial doubts but i don't even know the apt keywords to search for. every example i see in event binding ; i find no argument passed. some one Please help me out.
The value in your events hash can be a function definition. Thus you could do:
events: {
'click #category': function() { this.categorylist('somearg'); }
}
This will work if you want the same argument passed in every time. If you need arguments related to the element clicked, I can suggest adding a data attribute in the html, and retrieving it from event.target in the function.

Can someone explain why this is passing in an object

I have something like the following..
$(document).ready(function() {
$('#doReport').click(doReport);
});
function doReport(type) {
if (type === undefined) {
type = 'blah';
}
alert (type);
}
If I run doReport() from the console or standalone in the javascript with nothing in it, it will return 'blah' (as expected), and obviously if I call doReport('wibble'); it returns 'wibble' as you would expect.
But if I run it by clicking the element with ID doReport (utilising the bind I set up in .ready) it returns [object Object]
I don't understand why that would be the case.
The jQuery library passes your event handlers an "event" object. It will always be there. It's a "wrapped" or "fixed" version of the native browser object, making it somewhat easier to deal with.
Here is the documentation for such objects.
Also of note is the fact that jQuery will invoke your handler functions such that this refers to the DOM element for which the handler is being invoked.
Also also, as #Ericson578 points out in a good comment, jQuery allows additional parameters to be set up, which means that your handler may be passed additional parameters. That might be useful if you've got a single event handler function to be bound to different elements, but you'd like to qualify its behavior with some different flags or whatever based on the particulars of an element.
Event handlers receive an event object as a parameter.
This is because event handlers are triggered with an object (specifically, the event object) passed as the first argument.
This is the reason you see such syntax as
$('#doReport').click(function(e) {
If you want to call your function without any parameters, you'll need to create a wrapping function to do so:
$(document).ready(function() {
$('#doReport').click(function() {
doReport();
});
});
When jQuery calls the function passed as parameter to click, it passed event object as the argument hence you are getting the alert as [object Object].
Check this:
http://api.jquery.com/click/
From JQuery - .click()
.click( handler(eventObject) )
handler(eventObject)A function to execute each time the event is triggered.
Your doReport() function is getting an event object.
wrap it with another function if you need to pass an argument to your function.
$(document).ready(function() {
$('#doReport').click(function(event){
doReport('blah');
});
});

Clean way to pass parameters between JavaScript events?

I have values I would like to keep in memory when certain events fire, like when a user is dragging and I want to save the element index. The value is needed when another event might fire. I don't know if it will ever fire.
I am using global variables to keep these values around. It seems there are better ways to do this like putting these values in an object with a namespace. Benefits? Any other suggestions?
My alltime favorite is currying variables into event handlers. Curry is a function prototype and when called on a function it will return a version of the function with preset arguments:
Function.prototype.curry = function curry() {
var fn = this, args = Array.prototype.slice.call(arguments);
return function curryed() {
return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
};
};
node.addEventListener('mousedown', handler.curry(var1,var2,etc));
You could bind the data to a parent element that is a relevant container for each value. So for example, say you have a #dragAndDropContainer, in which there are many drag and droppable items, then as soon as a drag event fires (i.e. a drag begins), you could (in jQuery), execute:
$('#dragAndDropContainer').data('lastDragged', $(this).attr('id'));
And then just query $('#dragAndDropContainer').data('lastDragged') every time you need to.
I like davin's solution, but here is an alternative if that doesn't suit you. You can create a closure around the event handler like so:
var data = { x: 1, y: 2 };
var handler = function() {
console.log(data);
}
if (node.addEventListener) {
node.addEventListener('mousedown', handler, false);
} else {
node.attachEvent('onmousedown', handler);
}
An alternative to using Function.bind (sometimes known as curry): You can control the scope of your shared variable. Here's some jQuery pseudo-code demonstrating it. Shared is accessible to those two handlers and nobody else.
$(function(){
var shared = {a:1, b:2};
$('#id-1').click(function() {
alert(shared.a);
});
$('#id-2').click(function() {
alert(shared.b);
});
});
If you're writing jQuery procedural code, the closure approach is much simpler. Since most everything I write is an object, I'd rather not get into too many levels of inner closures, so I prefer to setup a handler with binding/currying (like Martin's example) if a handler needs access to shared variables.

jQuery: adding change event handler with predefined function

So I have the following:
var change_handler = function(element) {
// ... do some fancy stuff ...
}
Now, I want to attach this to an element. Which is the better/best or more correct method?
$('element_selector').change(change_handler(this));
Or...
$('element_selector').change(function() { change_handler(this); });
And does it make any difference if you're passing the object to the function or not?
Neither..
$('element_selector').change(change_handler);
change_handler will be the so to speak pointer to the method and the argument of the element is already passed by jQuery
If you were to use $('element_selector').change(change_handler(this)); it wouldn't actually assign the method as the handler but rather run the method and attempt to assign the result as the handler, the other option is superfluous because you can use the method name as described above instead of re-wrapping the method.
This is another way to approach the problem given by the OP... partial function application a la another SO Q. Bind the change handler with the arg of interest and pass the resulting partial as the arg to the change handler:
var myChangeHandler = partial(change_handler, this);
$('element_selector').change(myChangeHandler);

Categories