views:

157

answers:

5

Hi, Let say I have the following code

$("p").bind("click", function(){
  alert( $(this).text() );
});

When the user clicks a <p>, an alert show up. What's good here, is that I make use of the "this" keyword.

Now I want to get rid of the anonymous function (using it multiple time per script);

$("p").bind("click", myfunction());
myfunction(){
  alert( $(this).text() );
}

this now refer to Window. How can i do to fix that?

Update:

A suggested solution by answerers that actually works

$(function(){
    $("p").bind("click", function() { myfunction($(this));});

    function myfunction(elem)
    {
      alert( elem.text() );
    }
});

This is good, but you'll finish creating a new function every time that line of code is called, no?

+2  A: 

Something like

$(function(){
    $("p").bind("click", function() { myfunction($(this));});

    function myfunction(elem)
    {
      alert( elem.text() );
    }
});

Here also you are not removing the anonymous function. But inside that you can call another function.

rahul
The answer is passing this as an argument to the function, not as the context of the function.
Larry K
does solve the problem, but you'll finish creating a new anonymous function every time; imagine a table with 400 row, create 400 new function?
Omar Abid
@Omar Unless you can point to something telling me wrong, I think it's going to create only one function and point all the `p` click handlers to the one function. I wouldn't optimize before I know it's a problem...
Jonathon
I just gave <p> as an example. I'm using a loop over some table rows and binding that anonymous function each time. So doesn't it create new functions? It should. and this is why I want to make use of non-anonymous functions to avoid creating multiple functions.
Omar Abid
@Omar It creates a closure. If you have multiple elements, you should **not** be looping over them. You need to select all the elements you want using an appropriate jQuery selector and bind once.
Jonathon
+2  A: 

You want to pass the original "this" (the context) to the function.

In Javascript, that's done by using call. Eg, see here

So I modify Jonathon's answer:

$("p").bind("click", function(){ myFunction.call(this); });

function myfunction(){
  alert($(this).text());
}

Added:

I looked up jquery bind and Jonathon is right, the context is automatically set to be the original element that you're adding the event listener to.

I think the real issue is that you're not passing in the function ref correctly.

Try

$("p").bind("click", myfunction);
var myfunction = function(){
  alert( $(this).text() );
}
Larry K
rahul posted it before I did. jQuery already sets `this` to be the `p` that you clicked on, so the additional `call` is unnecessary. rahul's answer is fine; in fact if I'm making a generic `myFunction`, I'd rather pass an element to act upon to the function than require my caller to use `call` or `apply`.
Jonathon
Good catch on the function reference, forgot to mention that.
Jonathon
you are passing the function without arguments? What about if you have arguments?
Omar Abid
@Omar You're passing a **reference** to the function. The way you showed in your question, you evaluate the function and pass the return value to the bind, which doesn't make much sense. If you have arguments, you can wrap it in a function call like rahul's solution does.
Jonathon
@Omar, You mean you want your event-handling function to have access to additional information/arguments? See http://api.jquery.com/bind/ -- see the "Passing Event Data" section of the page.If you mean how do I use the call statement and send arguments in addition to context, the answer is place them as additional args to the call. Eg myfunction.call(thisObj, arg1, arg2, etc)
Larry K
+1  A: 

I was just thinking, why would you want to do it that way?

$("p").bind("click", function(){
  alert( $(this).text() );
});

when you can add up more selector like this:

$("p,div,li,:button").bind("click", function(){
  alert( $(this).text() );
});
Reigel
I wondered the same thing, but you could conceivably have some method you want to call from several places including a click handler.
Jonathon
+1  A: 

You can do this to get the real element that invoked the handler..

function myfunc(e)
{
  var _this = e.currentTarget;
  alert( $(_this).text());
}

according to jQuery documentation

event.currentTarget

Description: The current DOM element within the event bubbling phase.

version added: 1.3

This property will always be equal to the this of the function.

Gaby
Using the jQuery event argument is on the right track, but currentTarget won't help in this case. currentTarget would be `window` in the example shown in the question.
Dave Ward
Nope.. currentTarget since i extract it from the e parameter, which is the actual event passed from the jQuery binding, will point to the actual element handling the event.. try it at : http://jsbin.com/awuzo/2
Gaby
A: 

The problem there was that your event handler was calling the function, myfunction(), versus passing a reference to it, myfunction. That's what changed the scope it was running in. If you pass the function a parameter, myfunction, "this" should work as expected.

More generally, if all you really care about is knowing which element raised the event, use the normalized event object that jQuery passes into event handlers:

$("p").bind("click", function(evt) {
  // this === evt.target;

  alert($(evt.target).text());
});

Or:

$("p").bind("click", myfunction);

myfunction(evt) {
  alert($(evt.target).text());
}
Dave Ward