I was wondering how to use the $(this) selector in a function. I have tried multiple ways found on the internet but none seem to work.
Here's an example of what I'm trying to do
function bobsCar() {
$(this).toggle();
}
$('p').click(function() {
bobsCar();
});
Another option is to execute the function with a custom context like.
function bobsCar() {
$(this).toggle();
}
$('p').click(function() {
bobsCar.call(this);
});
In your case since you are calling bobsCar without a context, this inside it refers to the window object that is why it is not working.
Function.call()
function bobsCar() {
$(this).toggle();
}
jQuery('p').click(function() {
bobsCar.call(this);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>click me</p>
You need to understand JavaScript contexts. By default if you call a method inside your click callback, it will use the global context (in this case window - try console logging this in your broken function), not the one in the callback. You can use call or apply to specify the context (in this case this refers to the DOMNode element in the callback, so we pass the same context to the function and it works).
This is a good article on the topic: http://yehudakatz.com/2011/08/11/understanding-JavaScript-function-invocation-and-this/
The value of this inside the click event handler is not a string representation of a selector. It is a DOM node.
If you want to override the normal value of this for a function, you can specify it with call or apply.
bobsCar.call(this);
You could pass it as an argument instead.
bobsCar(this);
function bobsCar(domNode) {
$(domNode).toggle();
}
You should probably just use the function as the event handler in the first place though.
$('p').click(bobsCar);
You cannot directly use this in called function. You must have to pass selected object as function argument.
function bobsCar(element) {
$(element).toggle();
}
$('p').click(function() {
bobsCar(this);
});
This inside the function no longer reefers tot he 'p' tag, you could pass it
function bobsCar(el) {
el.toggle();
}
$('p').click(function() {
bobsCar($(this));
});
In JavaScript the $(this) is a context-pointer. It gives you the top-most context that is placed on the stack.
function bobsCar(elm) { console.log(elm);
$(elm).parent().toggleClass(); }
$('p').click(function() { var $this=$(this); bobsCar($this); });
jsfiddle.net/q325d6zw
Related
I'm using jQuery and I have a function that serves as an event callback, and so in that function "this" represents the object that that captured the event. However, there's an instance where I want to call the function explicitly from another function - how do I set what "this" will equal within the function in this case?
For example:
function handleEvent(event) {
$(this).removeClass("sad").addClass("happy");
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
handleEvent(e); // in this case, "this" will be the window object
// but I'd like to set it to be, say, the input in question
}
}
Use apply call.
handleEvent.call(this, e);
Just parameterize the function you're interested in:
function doStuff(el) {
$(el).removeClass("sad").addClass("happy");
}
function handleEvent(event) {
doStuff(this);
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
doStuff(this);
}
}
Use
e.target
I'd advice you re-factoring your function as a jQuery plugin.
But here's a quick Fix:
handleEvent.apply(this,e) //transfers this from one scope, to another
If you're simply looking to call a single event handler as if it were being triggered normally, apply/call will work fine. However, depending on your needs, it may be more robust to use the zero-argument version of jQuery's click() function, which will trigger all click handlers for that element:
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
$(this).click(); // simulate a click
}
}
If I originally have a click event handler in jQuery like this
jQuery('#btn').click(_eventHandler);
Which then handles the event like
function _eventHandler(e){
jQuery(this).text('Clicked');
}
then the this keyword exacts as an alias to the DOM element of the button that was clicked, correct?
But now, I need to change this logic so there is a flag to check for something else like
jQuery('#btn').click(function(e){
if(blah){
_eventHandler(e);
}else{
_dosomethingElse(e);
}
});
then will the this keyword in _eventHandler still work correctly? I basically need to do a check before the _eventHandler is called, but I do not want to change the actual function for the _eventHandler and place this logic inside there. Will this still work?
If you want this set in your functions, you can use .call() to cause it to be set accordingly:
jQuery('#btn').click(function(e){
if(blah) {
_eventHandler.call(this, e);
} else {
_dosomethingElse.call(this, e);
}
});
This allows you to use the same function either called by yourself or as a direct event handler because this and the arguments will be set identically.
Every function has both a .call() and .apply() method which allow you to set the this value when calling a function. You would use .call() when you have a specific number of arguments to pass and you would use .apply() if you have an array of arguments (often of unknown length). See MDN for more info.
you can pass its reference in the methods:
jQuery('#btn').click(function(e){
if(blah){
_eventHandler(e,this);
}else{
_dosomethingElse(e,this);
}
});
and access them in function:
function _dosomethingElse(event,element)
{
$(element).text("Else called");
}
function _eventHandler(event,element)
{
$(element).text("Event Called");
}
Note: By this way now _eventHandler cannot be used as direct event handler for button click,because it is not now a direct event handler as you were doing preciously this way jQuery('#btn').click(_eventHandler); but now it is different.
Just to clarify to the answer already given, "this" keyword always refers to the object that the function or method is operating off of. So in your function '_eventHandler' this was refering to the '_eventHandler' function. Jquery passes the 'selector' object to each of it methods so you could make event handler and extenstion on jQuery prototype. like this...(by the way Jquery.fn = jQuery.prototype
jQuery.fn._eventHandler= function () {
jQuery(this).text('Clicked');
}
... and call is like
jQuery('.yourSelector').click(function() {
jQuery(this)._eventHandler();
});
...and jquery would pass the yourSelecotr as 'this'
You can simply try it out:
function fn(ev) {
console.log('fn ' + this);
}
$('button').click(function (ev) {
function nested(ev) {
console.log('nested ' + this);
}
console.log('click ' + this);
fn(ev);
nested(ev);
fn.call(this, ev);
});
Output:
"click [object HTMLButtonElement]"
"fn [object Window]"
"nested [object Window]"
"fn [object HTMLButtonElement]"
this context is set to window when you call a function. You can use the method Function.prototype.call(thisContext [, arg1 ...]) to set the this context explicitly.
For example :
function masterMethod(this, action){
// (action); <-- But action requires $(this) to be defined.
}
$(".item").click(function(){
function minorMethod(){
alert($(this));
}
masterMethod($(this), minorMethod)
});
How would I execute the action and pass $(this) in the masterMethod?
You can use call [MDN]:
function masterMethod(element, action){
action.call(element);
}
$(".item").click(function(){
function minorMethod(){
alert($(this));
}
masterMethod(this, minorMethod)
// or directly here?
// minorMethod.call(this)
});
Note the two changes I made: Instead of passing $(this) to masterMethod, I passed this (the DOM element), since inside minorMethod, you are passing this again to jQuery. If you were passing $(this) you would end up passing a jQuery object to jQuery again, i.e. $($(this)), which is unnecessary.
I'm not sure if it actually would throw an error, but in any case, you should not name your argument this.
Typically, when needing to access an event, you do so via the parameter specified in the callback function:
$button.live("click", function(ev) {
// do something with ev here, like check 'ev.target'
}
But instead (for reasons too complicated to get into here), I do not want to use an anonymous callback function, but instead specify a function to call, like this:
$button.live("click", functionToCall(ev, $(this));
So you'll notice that I included 'ev' as a parameter to functionToCall(), but this obviously won't work because I'm not using the anonymous callback function. But I do still need to access that click event (to check ev.target) within functionToCall(). My question is, how do I access this event? It would be nice if I could do something like this:
$button.live("click", functionToCall($(this));
and
function functionToCall($item) {
var target = $item.event("click").target;
// do something with target
}
Any ideas would be very much appreciated. Thanks.
Original answer
function test(eve) {
alert(eve.type);
alert(this);
//$(this) if you need it as jQuery object
}
$([yourselector]).live("click", test);
You will automatically get the event in the eve parameter.
Answer to extended question in comment
Passing in a parameter makes it a little more difficult. If you need an explanation why I did it like this: Ask.
function helper(customparam) {
return function(eve, selector) { actualFunction(eve, selector, customparam, this) };
}
function actualFunction(eve, selector, customparam, self) {
alert(eve.type);
alert(selector);
alert(customparam);
alert(self); //self is now the element we clicked on
//$(self) if you need it as jQuery object
//using this won't work anymore as this is now window
}
$([yourselector]).live("click", helper([yourparameter]));
You could call a function within the anonymous callback function:
$button.live("click", function(ev) {
functionToCall(ev, $(this));
}
EDIT: I think this may be what you're looking to do (untested):
function handleClick(ev) {
$(this).die("click");
// ...whatever processing to do...
$(this).live("click", handleClick);
}
$button.live("click", handleClick);
I believe the $(this) will refer to the button object in which the function was called.
Remember that jQuery re-assigns this when it calls event handlers, by using the Function methods call or apply. So when functionToCall is invoked, this is the DOM element of $button.
var functionToCall(ev) {
var $this = $(this);
$this.die("click", functionToCall);
// stuff
$this.live("click", functionToCall);
}
$button.live("click", functionToCall);
var mythis = $(this);
var callback = function(ev) {
var target = mythis.event("click").target;
}
$button.live("click", callback);
I'm using jQuery and I have a function that serves as an event callback, and so in that function "this" represents the object that that captured the event. However, there's an instance where I want to call the function explicitly from another function - how do I set what "this" will equal within the function in this case?
For example:
function handleEvent(event) {
$(this).removeClass("sad").addClass("happy");
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
handleEvent(e); // in this case, "this" will be the window object
// but I'd like to set it to be, say, the input in question
}
}
Use apply call.
handleEvent.call(this, e);
Just parameterize the function you're interested in:
function doStuff(el) {
$(el).removeClass("sad").addClass("happy");
}
function handleEvent(event) {
doStuff(this);
}
$("a.sad").click(handleEvent); // in this case, "this" is the anchor clicked
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
doStuff(this);
}
}
Use
e.target
I'd advice you re-factoring your function as a jQuery plugin.
But here's a quick Fix:
handleEvent.apply(this,e) //transfers this from one scope, to another
If you're simply looking to call a single event handler as if it were being triggered normally, apply/call will work fine. However, depending on your needs, it may be more robust to use the zero-argument version of jQuery's click() function, which will trigger all click handlers for that element:
function differentEvent(event) {
$("input.sad").keydown(e) {
doSomeOtherProcessing();
$(this).click(); // simulate a click
}
}