Why must callbacks in jQuery be anonomous? - javascript

This works just as expected but I don't like it.
$('#login-form').on('submit', function(event){
event.preventDefault();
init.login();
});
var init = {
login: function() {
// do login stuff
}
};
This is what I want but it does not work.
$('#login-form').on('submit', init.login(event));
var init = {
login: function(event) {
event.preventDefault();
// do login stuff
}
};
Why?

It will work, you're calling the function (the value given as a callback will be the result of the function) rather than passing it as a value
$('#login-form').on('submit', init.login);

init.login(event) calls the function init.login, passing the (non-existent) variable event to it. If you want to pass the function itself as callback, don't call it:
$('#login-form').on('submit', init.login);
You will have to declare that function before you pass it though, at this point init.login is undefined.

You're already calling the function in that line (with undefined, there is no event yet). You need to pass the function itself (not its result):
$('#login-form').on('submit', init.login);
Notice that init.login is still an anonymous function, it has no name :-) Also beware that the method is called with this being the login form element, not the init object. If you needed that, you'd use .on('submit', init.login.bind(init)).

Related

Javascript convert anonymous function to named function passing clicked object [duplicate]

I have the following script which does not work
<script type="text/javascript" >
function ADS(e){ alert(e); }
$(document).ready(function(){
$(document).on("dblclick","#an_tnam tr", ADS('hello'));
$(document).on("dblclick","#kv_tnam tr", ADS('world'));
// ....
});
</script>
how can I pass argument to event handler function ADS ?
You can pass extra data to an event handling function and can be accessed using event.data within the handler.
$(document).on('dblclick', '#an_tnam tr', { extra : 'random string' }, function(event)
{
var data = event.data;
// Prints 'random string' to the console
console.log(data.extra);
}
You can also send extra data to any event you like when triggering the event from an external source using the .trigger() method
$('#an_tnam tr').trigger('click', [{ extra : 'random string' }]);
The difference with passing data to the .trigger() method is that .on() expects the handler to take extra arguments of the length of the array passed in. The above would expect the handler to have (only) one extra argument to contain the object passed in.
$('#an_tnam tr').on('click', function(event, obj)
{
// Prints 'random string' to the console
console.log(obj.extra);
}
The .on() function expects a function reference to be passed; what you're doing is calling the function and passing its return value. If you need to pass a parameter you'll need to wrap the call in an anonymous function.
$(document).on('dblclick', '#an_tnam tr', function(event) {
ADS('hello');
});
jQuery always passes its normalized event object as the first argument to the function to be executed.
Actually, there is a very neat simple way to achieve this, with no extra clutter and no anonymous functions, using JS bind():
$(document).on('dblclick', ADS.bind(null, 'hello'));
First parameter is the value you want "this" to have inside callback function.
MOre info in Mozilla Developer Network: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
As Anthony Grist pointed out, the .on() method is expecting a function reference at that part; you're evaluating a function which returns nothing (null).
However, one fun feature of JavaScript is that everything is an object, including functions. With a small modification, you can change ADS() to return an anonymous function object instead:
function ADS(e){
return function(){ alert(e); };
}
http://jsfiddle.net/cSbWb/
function ADS(e){ alert(e); }
$(document).ready(function(){
$(document).on("dblclick","#an_tnam tr", function (e) { ADS('hello') });
});
will do the trick.
function ADS(e) {
return function() {
alert(e);
};
}
Like that when you're doing
$(document).on("dblclick","#an_tnam tr", ADS('hello'));
, it is the returned function that is assigned as event handler (and your string argument is passed when you're assigning the handler, not when it's called).

onclick assigned function with parameters

I'm not sure if this has been asked before because I don't know what it's called.
But why wouldn't a method like this work? Below is just a general example
<script>
document.getElementById('main_div').onclick=clickie(argument1,argument2);
function clickie(parameter1,parameter2){
//code here
}
</script>
The code above would work fine if the event handler was assigned without parameters, but with parameters, it doesn't work. I think I read online that to overcome this problem, you could use closures. I'm assuming it's because of the parentheses ( ) that is calling the function immediately instead of assigning it to the event?
Because you're calling the function immediately and returning the result, not referencing it.
When adding the parenthesis you call the function and pass the result back to onclick
document.getElementById('main_div').onclick = clickie(); // returns undefined
so it's actually equal to writing
document.getElementById('main_div').onclick = undefined;
which is not what you want, you want
document.getElementById('main_div').onclick = clickie;
but then you can't pass arguments, so to do that you could use an anonymous function as well
document.getElementById('main_div').onclick = function() {
clickie(argument1,argument2);
}
or use bind
document.getElementById('main_div').onclick = yourFunc.bind(this, [argument1, argument2]);
It is however generally better to use addEventListener to attach event listeners, but the same principle applies, it's either (without arguments)
document.getElementById('main_div').addEventListener('click', clickie, false);
or bind or the anonymous function to pass arguments etc.
document.getElementById('main_div').addEventListener('click', function() {
clickie(argument1,argument2);
}, false);
The easiest way is:
yourElement.onclick = yourFunc.bind(this, [arg1, arg2]);
function yourFunc (args, event) {
// here you can work with you array of the arguments 'args'
}
When you say onClick = function() {...} you are registering your function with some internal JavaScript library. So when the "click" happens, that library invokes your function.
Now imagine you're the author of that library and someone registered their function with it. How would you know how many parameters to pass to the function? How would you know know what kind of parameters to pass in?
clickie(argument1,argument2)
This means to invoke the function and return its return value.
clickie
This simply is a reference to the function (doesn't invoke/execute it)
To bind an event to a element, you need to use either the attachEvent or addEventListener method. For example.
/* Non IE*/
document.getElementById('main_div').addEventListener('click', function () {}, false);
/* IE */
document.getElementById('main_div').attachEvent('onclick', function () {});
A function name followed by parentheses is interpreted as a function call or the start of a function declaration. The a onclick property needs to be set to a function object. A function declaration is a statement, and is not itself a function. It doesn't return a reference to the function. Instead it has the side effect of creating a variable in the global scope that refers to a new function object.
function clickie(param) { return true; }
creates a global variable named clickie that refers to a function object. One could then assign that object as an event handler like so: element.onclick = clickie;. An anonymous function declaration (often confused with a closure; for the difference see Closure vs Anonymous function (difference?)) does return a function object and can be assigned to a property as an event handler, as follows:
element.onclick = function(event) { return true; };
But this doesn't work:
element.onclick = function clickie(event) { return true;};
Why? Because function clickie(event) { return true;} is a statement, not a function. It doesn't return anything. So there is nothing to be assigned to the onclick property. Hope this helps.

javascript passing event in closure

I was trying the following:
f.addEventListener('submit',(function(frm){
var func = (function(e){somefunction(e,frm);})(e);
})(f),false);
But this is failing. I want to pass the form (f) as a static reference and the dynamic event object to the named function 'somefunction'.
What I have above isnt working, what is the right syntax for passing both?
The issue is that each of the functions is being called right away, with undefined actually being passed to addEventListener().
You'll want to instead return one of the functions without its calling parenthesis so the event can call it later:
f.addEventListener('submit', (function (frm) {
return function (e) {
someFunction(e, frm);
};
})(f), false);
Though, with event bindings, you may not necessarily need the closure, as the <form> will be the context (this) of the function passed:
f.addEventListener('submit', someFunction, false);
function someFunction(e) {
var frm = this;
// ...
}
not saure exactly what you are trying to do but, to looks like you are trying to manually pass in the form via the event handler. Instead save a reference and just refer to it in the handler such as
f.addEventListener('submit',function(){
var func = function(e){
somefunction(e,f);
};
},false);
you shouldn't need the self executing functions unless I am missing your intent here

onclick call with params

I've got a function, like this:
menu[0].onclick = function() {
filters.reset_all();
clients.get();
}
So it's called when user clicks on the first menu element. Now I need to call it form the other place and what I've done is this:
if (li.onclick) { //li and menu[0] above are the same
li.onclick.call();
}
and it works well.
But now I need to pass some params to onclick function. I've tried this .call(some_param); but arguments array in onclick is empty.
What am I doing wrong?
edit: changed into this:
menu[0].onclick = function(arg) {
console.log(arg);
filters.reset_all();
clients.get();
}
and
li.onclick.call(li,param);
still nothing
The first argument to .call() is the value for the this pointer. The 2nd, 3rd, etc... arguments get passed to the function. You only need to use .call() if you're explicitly trying to set the this pointer. Otherwise, you can just directly call the function li.onclick().
Event handlers are generally called by the system and when that happens, they are passed the event object as the first argument. If you want a function available that takes different arguments, you should create your own function for that and not use the event handling function. Your event handler can also call this other function if desired.
menu[0].onclick = function() {
myFunc("aaa");
}
function myFunc(arg1) {
// do whatever here
filters.reset_all();
clients.get();
}
if (li.onclick) {
myFunc("bbb");
}
it should be
call(object, param1, param2, param3...);
In your case you can write
li.onclick.call(li, param1);
The first parameter of call() is the context (in this case this) the rest of the parameters go into the arguments array in order. If you use apply() instead of call then you have just two parameters: apply(this, arguments_array)

How to decide if a parameter is the click event

I have a function which can be called by either a click event or directly. When I call it directly, I need pass it a data parameter, so I've defined the function to accept a parameter to account for the direct call with the parameter.
function myFunc(param){
}
Within the function, I need to differentiate whether the function was called directly or from the click event, so what I thought I could simply check if param is set. If it's set, then the function is called directly. If it's not set, then it's called from the click event.
The problem is that a click event by default passes an event object. So even when the function is called by the click event, param won't be null.
So is there a way to check whether the param passed is the click event?
You don't need to duplicate any code. The proper way to do this is to handle the click event with an event handler, and the action you want to take in another function. For example:
// define main action
var doSomethingUseful = function(is_clicked) {
// write some code here
}
// define click handler
var myBtnClicked = function(e) {
doSomethingUseful(true);
}
// bind click event
$('#my_button').click(myBtnClicked);
Although, as was already mentioned to you, the fact that you need to know that information is usually a warning sign that there might be a simpler way to do things.
edit for example:
// define main action
var doSomethingUseful = function() {
// write some code here that doesn't care "why" it's being called
}
// define click handler
var myBtnClicked = function(e) {
// do the click-only stuff
// call the generic function
doSomethingUseful();
}
// bind click event
$('#my_button').click(myBtnClicked);
IE's before version 9 don't always pass the event argument, so the parameter will be be undefined if it is called from an IE click.
function myFunc(param){
if(!param) || param.clientX)// not called with a data param
}
You would do better to check for the data than for the event.
Check for the .clientX property that is passed to the click event.
function(param){
if(param.clientX){//this is a click event}
else
{//this is a call event};
};
You may want to use this one.
function(param){
if(param.target){//this is a click event}
else
{//this is a call event};
};
function myFunc(param) {
// which (aka keyCode) is a property set to params
// by jQuery for any event
// Check for object make you free to pass parameter
// as object also with string, array and so on
if (Object.prototype.toString(param) == '[object Object]' && param.which) {
// called by clck
console.log(param.which);
} else {
// called by function
console.log(param);
}
}
$('#clickable').click(myFunc)
// passing parameter as object
myFunc({
a: 'abc',
b: 'def'
});​
// passing parameter as string
myFunc('Hello');
// passing parameter as array
myFunc([1, 2, 2]);
and so on.
DEMO
jQuery(document).ready(function(){
$('#someID').click(function(){
myFunc(true);
});
myFunc();
});
function myFunc(param){
param ? alert("click"):alert("not click");
}

Categories

Resources