jQuery: adding change event handler with predefined function - javascript

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);

Related

Function parameter evaluates to undefined

When dynamically creating an element of type select, there are two problems when setting the onclick method:
It is impossible to simply set the onclick with element.onclick="updateInput(this.articleIndex)";
This results in a final HTML tag where no onclick is shown at all.
When set by e.setAttribute("onclick","updateInput(this.articleIndex)");, it does appear in the final HTML. And the updateInput method does get called.
However the functionality seems to be broken, as the argument always evaluates to undefined
Here a simple example of my problems:
var selectElem = document.createElement("select");
selElem.id="articleSelector_"+this.articleIndex;
console.log("the index of the article is " + this.articleIndex);
selElem.setAttribute("onclick","updateInput(this.articleIndex);");
//selElem.onclick="updateInput(this.articleIndex)"; //this does not work
The log shows the correct number. Inside the updateInput method, the argument is of value undefined instead of the number previously shown in the log.
Try attaching handlers with pure Javascript, and not with HTML, without onclick = "... (which is as bad as eval).
The this in your script refers to the calling context of the function - what is it?
You might want:
element.addEventListener('click', () => {
updateInput(this.articleIndex);
});
(arrow functions retain the this of their surrounding scope)
it is impossible to simply set the onclick with element.onclick="updateInput(this.articleIndex)";
What that code does is it assigns the string "updateInput(this.articleIndex)" to the onclick which makes no sense and certainly not what you want.
Even if you remove the quotes:
element.onclick = updateInput(this.articleIndex);
It is still incorrect because it assigns the result of the updateInput() function to the onclick which is again not what you want.
You need to assign a function name to the onclick like this:
element.onclick = updateInput;
However, this doesn't allow you to pass a parameter as you wish. To do so, you need to use an anonymous function:
element.onclick = function() {
updateInput(this.articleIndex)
};
When set by e.setAttribute("onclick","updateInput(this.articleIndex)");, it does appear in the final HTML. And the updateInput method does get called.
This works because it sets the attribute onclick and it is a string type, so everything is correct. It is equivalent to using the anonymous function above. The only difference is this, which in this case refers to the element itself, while in the above code it depends on the context that the code appears in. That's why in this case the argument always evaluates to undefined because the select element doesn't have an articleIndex property.
The problem is the value of the context this when that element is clicked, the context this is not available anymore at that moment.
You have two ways to solve this problem:
You can use the function addEventListener to bind the event click, and bind the function/handler with the desired context this:
The function bind binds a specific context to a function.
selElem.addEventListener('click', updateInput.bind(this));
function updateInput() {
console.log(this.articleIndex);
}
As you need a specific value, you can use data attributes. That way, you don't need to worry about the context this.
selElem.dataset.articleIndex = this.articleIndex;
selElem.addEventListener('click', function() {
updateInput(this.dataset.articleIndex); // Here you can get that value.
});

How to pass event and other arguments to click handler

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.

Pass paramtes to event function

I bulid a function to event and I want to know how can I pass parameters to that function?
I use addEventListener method to add events
What I need is to pass the element variable to the function mean this object
For example if I use attribute method to add event I do like this:
<div onclick="function(this)">
And then the function will get the div element
Now my question is how can I pass the this object to the function when I use addEventListener
Is there anyway to get this thing?
Blah.addEventListener(function(event){
var element = event.target;
});
Posted from phone. Please forgive
http://www.w3schools.com/jsref/met_document_addeventlistener.asp
Define your listener with a parameter, this will be an event object.
In this object you will find the triggered element.
In an event handler, such as onclick, 'this' will automatically point to the element, where the event is triggered. You can use it inside your anonymous function.
Note: It's not a string but a HtmlElement.
Hope I have understood your question correctly.

Computed binding doesn't work with on-click (Polymer)

<template is="dom-repeat" items="{{myItems}}">
<div on-click="{{ComputedBindingFunction(item)}}">Foo</div>
</template>
This yields an error saying:
listener method {{ComputedBindingFunction(item)}} not defined
Shouldn't the function be executed, instead of literally trying to attach the function name with {{}}'s to on-click according to the docs?
Note that ComputedBindingFunction returns a function.
The example shown in the documentation you link to isn't for calling methods or firing events, it's for using computed bindings.
i.e.
<div>{{ComputedBindingFunction(item)}}</div>
If you're your trying to trigger an event, remove the braces:
<div on-click="ComputedBindingFunction"></div>
...
Access item from the triggered event
ComputedBindingFunction: function(event){
_ComputedBindingFunction(event.model.item)
}
Firstly, Attributes for event listeners (e.g., on-click, on-tap, etc) don't allow computed bindings as an argument, only a string.
Secondly, even if they did, which would be super cool in the future, your example still wouldn't work because you are returning a function from the computed binding and not a string.
Your computedFunction should instead be returning the name of the function you want to call which is defined using the arguments supplied when the event is fired.
Example:
html polymer event handler attribute
<div on-click="{{computeFunction(a, b}}">Button</div>
computeFunction makes a new function "add" and returns the name of this function as a string.
computeFunction: function(a, b) {
functionName = "add";
this[functionName] = function() {
// Does whatever you want with arguments, a, b
// Like maybe adding them together.
return a + b
}
return functionName;
}
add: function(a, b) {
return a + b;
}
This way the function called "add" which is called when the on-click event occurs would always be using the new variables "a" and "b" assigned to it.
Until this is available, which it might be never, You can store parameters in an attribute on the element which fires the event.
<div on-click="someFunction" someFunction="{{item}}">Button</div>
someFunction: function(e) {
// Current target is the node that fired the event,
// It has our stored parameter "{{item}}" as a value of "someFunction"
var item = e.currentTarget.getAttribute('someFunction');
// Do something with item
console.log(item);
}
As you can see I stored the item in an attribute with the name of the function called by the on-click event.
This way it's easy to tell what arguments are going to be passed to the function just from looking at the html, and works for multiple event handlers on the same element.

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');
});
});

Categories