views:

437

answers:

5

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!

+6  A: 

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
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
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
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
+3  A: 

$("#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?

Sean Nyman
A: 

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

$("#myelement").click(sayHello);
Derferman
+4  A: 

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.

Chris Brandsma
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
submitted additional information!
yuval
@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
@shog9: i see... how is that done?
yuval
@yuval: i've expanded Chris's example.
Shog9
@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
@Shog9, thank you for expanding the example.
Chris Brandsma
+1  A: 

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);
}
Dr.Dredel
Not a direct answer to the question (since he's using jQuery), but upvoted because it's a great Javascript tip nonetheless.
DisgruntledGoat
interesting idea, but not quite what I am looking for...
yuval
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