12

I'm trying to execute an external function on click of a DOM element without wrapping it in another function.

Say I have a function called sayHello(), as follows:

function sayHello(){
  alert("hello");
};

To execute it on click, I currently have to do this:

$("#myelement").click(function(){
  sayHello();
});

Notice I am forced to wrap the single function call in yet another function. What I am trying to do is something like this

$("#myelement").click(sayHello());

Except that simply doesn't work. Can I avoid wrapping the single function call in another function in any way? Thanks!

.

Additional information: How would I achieve the same thing when I need to pass parameters to the function?

..

Additional information: Like Chris Brandsma and Jani Hartikainen pointed out, one should be able to use the bind function to pass parameters to the function without wrapping it in another anonymous function as such:

$("#myelement").bind("click", "john", sayHello);

with sayHello() now accepting a new parameter, as such:

function sayHello(name){
  alert("Hello, "+name);
}

This, unfortunately, does not seem to work... Any ideas? The Events/bind documentation is located here Thanks!

Yuval Karmi
  • 26,277
  • 39
  • 124
  • 175
  • What is your beef with wrapping functions? It's not a performance hit (well, nanoseconds maybe). It's a little verbose but I find it useful to do this and keep everything consistent. The second you need to add a parameter or call more than one function you'll need to add the wrapper back in... – DisgruntledGoat Jul 25 '09 at 23:42
  • 1
    i guess i just want to have it nicely in one line and i'm OCD like that... :) – Yuval Karmi Jul 25 '09 at 23:54

6 Answers6

21

To pick up from a question you had in there.

Obviously, you need to call it this way to work:

$("#myelement").click(sayHello);

Calling it the way you had it actually executes the method instead of sending the method to the click handler.

If you need to pass data you can also call the method this way:

$("#myelement").click(function(){ sayHello("tom");});

Or you can pass data via the bind() function

function sayHello(event){ alert("Hello, "+event.data); }

$("#myelement").bind("click", "tom", sayHello);

Or you can retrieve data from the element that was clicked

$("#myelement").click(function(){sayHello($(this).attr("hasData");});.

Hope that helps.

Shog9
  • 156,901
  • 35
  • 231
  • 235
Chris Brandsma
  • 11,666
  • 5
  • 47
  • 58
  • it follows from the "Events/bind" documentation on the jQuery website that this $("#myelement").bind("click", "tom", sayHello); should actually do what i am looking for... upon trying it though, it does not seem to work. I'll post some additional information in the original question in a second – Yuval Karmi Jul 25 '09 at 23:43
  • 1
    @yuval: read the docs more carefully! The value passed to `bind()` in the `data` parameter is passed to your handler via `event.data` - you need to interpret the first parameter to your function as an `event` object, and look at the `data` property! – Shog9 Jul 25 '09 at 23:53
  • 1
    @yuval: i've expanded Chris's example. – Shog9 Jul 25 '09 at 23:57
  • @shog9: perfect! this makes it much clearer. it's definitely easier to enclose a function call containing parameters in an anonymous function, though! thanks for your help! – Yuval Karmi Jul 26 '09 at 00:00
8

You are calling the sayHello-function, you can pass it by reference by removing the parenthesis:

$("#myelement").click(sayHello);

Edit: If you need to pass parameters to the sayHello-function, you will need to wrap it in another function. This defines a parameter-less new function that calls your function with the parameters provided at creation-time:

$("#myelement").click(function () {
   sayHello('name');
   // Creates an anonymous function that is called when #myelement is clicked.
   // The anonymous function invokes the sayHello-function
});
PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94
  • this actually works, but what do i do in a situation where i have parameters to pass to the function? i.e. $("#myelement").click(sayHello("john")); ? thanks! – Yuval Karmi Jul 25 '09 at 23:31
  • 1
    In that case you are forced to wrap it. Alternatively, some libraries like Prototype provide a bind() method which works something like sayHello.bind(this, param1, param2). It does exactly the same as wrapping it, though. – Jani Hartikainen Jul 25 '09 at 23:35
  • hey jani, it seems like this should work with jQuery's bind function too, but it does not. Please see the additional information to the question. thanks! – Yuval Karmi Jul 25 '09 at 23:49
4

$("#myelement").click(sayHello());

This is actually calling sayHello() before you set the click handler. It's trying to set the return value of sayHello() as the callback function!

Instead, try:

$("#myelement").click(sayHello);

And regarding your edit, if you need to pass parameters you can just use the closure technique you're already using, but if you're looking for something cleaner then check out How can I pass a reference to a function, with parameters?

Community
  • 1
  • 1
Sean
  • 4,450
  • 25
  • 22
1

what params would you be passing at the time of the click? if you know what they are in advance, you can set them before the user clicks.

you can't pass parameters but you can fake the parameter thing by simply adding members to the object which is firing the event, so..

myObject.onClick = sayHello;
myObject.param1 = "foo";

then, when you're calling this

function sayHello(){
  alert(this.param1);
}
Yevgeny Simkin
  • 27,946
  • 39
  • 137
  • 236
  • Not a direct answer to the question (since he's using jQuery), but upvoted because it's a great Javascript tip nonetheless. – DisgruntledGoat Jul 25 '09 at 23:45
  • IMHO, this is much less clean than an simple closure... at best, you have the extra work of setting expando properties on the DOM object, and at worst you could potentially run into naming collisions with built-in properties! – Shog9 Jul 25 '09 at 23:55
1

The bind() method is now deprecated.

As of jQuery 3.0, .bind() has been deprecated. It was superseded by the .on() method for attaching event handlers to a document since jQuery 1.7, so its use was already discouraged.

You are better off doing all event binding with the on() method for consistency. You can pass parameters to your handler as the second argument after the event name.

function sayHello(name){
    console.log('Hello ' + name);
};

$('#myelement').on('click', 'John', sayHello);
Udo E.
  • 2,665
  • 2
  • 21
  • 33
0

Yes, instead of passing sayHello(), just pass the function name.

$("#myelement").click(sayHello);
Derferman
  • 717
  • 5
  • 5