Pass $(this) to a function - javascript

I am trying to build a media playlist that can advance the credits, play the video and change the title on thumb-hover, end of video and on next/prev click. So I need to write some functions that can then be called together. So like this:
function showBox()
{
$(this).parents('.container').find('.box').show();
};
function hideBox()
{
$(this).parents('.container').find('.box').hide();
};
$('a').hover(
function()
{
showBox();
},
function()
{
hideBox();
}
);
The problem is that $(this) does not carry through to the functions from the .hover. How do I do this?

Per #patrickdw's answer, jQuery sets the scope of a callback for an event to the DOM element upon which the event was fired. For example, see the eventObject parameter in the documentation for the click() handler.
My original answer (below) is useful when you want to create a jQuery plug-in so that you may invoke your own custom methods on jQuery objects and have the jQuery object set as this during execution. However, it is not the correct and simple answer to the original question.
// Within a plug-in, `this` is already a jQuery object, not DOM reference
$.fn.showBox = function(){ this.parents('.container').find('.box').show(); };
$.fn.hideBox = function(){ this.parents('.container').find('.box').hide(); };
$('a').hover(
function(){ $(this).showBox() },
function(){ $(this).hideBox() }
);
Edit: Or, if (as suggested) you want to add only one name to the ~global jQuery method namespace:
$.fn.myBox = function(cmd){
this.closest('.container').find('.box')[cmd]();
};
$('a').hover(
function(){ $(this).myBox('show') },
function(){ $(this).myBox('hide') }
);
Or more generally:
$.fn.myBox = function(cmd){
switch(cmd){
case 'foo':
...
break;
case 'bar':
...
break;
}
return this;
};
For more information, see the jQuery Plugin Authoring Guide.

The this will carry through if you just do:
$('a').hover(showBox,hideBox);
EDIT: To address the question in the comment, this will work for any function you assign as an event handler. Doesn't matter if it is an anonymous function or a named one.
This:
$('a').click(function() {
alert( this.tagName );
});
...is the same as:
function alertMe() {
alert( this.tagName );
}
$('a').click( alertMe );
...or this:
function alertMe() {
alert( this.tagName );
}
$('a').bind('click', alertMe );

In Javascript you can use call() or apply() to execute a function and explicitly specify this for it:
$('a').hover(
function()
{
showBox.call(this);
},
function()
{
hideBox.call(this);
}
);
The first parameter given to call() specifies the object that this will refer to in the function. Any further parameters are used as parameters in the function call.

You need to modify your code to something like this:
function showBox(elem)
{
elem.parents('.container').find('.box').show();
};
function hideBox(elem)
{
elem.parents('.container').find('.box').hide();
};
$('a').hover(
function()
{
var $this = $(this);
showBox($this);
},
function()
{
var $this = $(this);
hideBox($this);
}
);

$('a').hover(function() {
$(this).closest('.container').find('.box').show();
}, function() {
$(this).closest('.container').find('.box').hide();
});

Add parameters to showBox and hideBox so that they can accept the element, and then call showBox($(this)) and hideBox($(this)).

Related

Pass $(this) to a Binded Callback Function

I am trying to understand the difference between these two callback methods and how they handle the $(this) context.
Working Example
$("#container").on("click",".button", function() {
$(this).text("foo");
});
This process works just fine. However, if I want to do a different approach, I lose the context of the event.
Non-Working Example
bindAnEventToAnElement: function(theElement, theEvent, theFunctions) {
$("body").on(theEvent, theElement, function() {
theFunctions();
});
}
bindAnEventToAnElement(".button", "click", function() {
$(this).text("foo");
});
The latter produces an undefined error. Is there a way I can handle callbacks like this while retaining the context of the event?
Fiddle
http://jsfiddle.net/szrjt6ta/
AFAIK, jquery's this in that callback function refers to the event.currentTarget value. So, you should also pass the event object and do something like this:
$("#container").on("click", ".button", function () {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function (theElement, theEvent, theFunctions) {
$("body").on(theEvent, theElement, function (e) {
theFunctions.apply(this /* or e.currentTarget */, arguments);
});
}
}
theApp.bindAnEventToAnElement(".button-two", "click", function () {
$(this).text("foo");
});
Working Fiddle
If I try to explain the problem, jquery is binding the callback function to pass this as e.currentTarget. But you are passing an another callback function inside that callback function whose scope will not be its parent callback function but will be the window. So, you need to again bind the this to the wrapped function, which you can do using apply or call.
You have to manually bind the context to the function in order to have this valorized inside your callback:
$("body").on(theEvent, theElement, function() {
theFunctions.apply(this);
});
example http://jsfiddle.net/szrjt6ta/1/
Find more about apply() here
you can pass the event, then use $(e.target)
https://jsfiddle.net/szrjt6ta/3/
Use .call(this) The call() method calls a function with a given this value and arguments provided individually.
Note: While the syntax of this function is almost identical to that of
apply(), the fundamental difference is that call() accepts an argument
list, while apply() accepts a single array of arguments.
$("#container").on("click",".button", function() {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function(theEvent, theElement, theFunctions) {
$("body").on(theEvent, theElement, function() {
theFunctions.call(this);
});
}
}
theApp.bindAnEventToAnElement("click", ".button-two", function() {
$(this).text("fooe");
});
Fiddle
Change the event handler attachment from
$("body").on(theEvent, theElement, function() {theFunctions();});
to
$("body " + theElement).on(theEvent, theFunctions);
Like this:
HTML:
<div id="container">
<a class="button">Button</a><br />
<a class="button-two">Button Binded</a>
</div>
JQuery:
$("#container").on("click",".button", function() {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function(theElement, theEvent, theFunctions) {
$("body " + theElement).on(theEvent, theFunctions);
}
}
theApp.bindAnEventToAnElement(".button-two", "click", function() {
$(this).text("foo");
});
Fiddle: https://jsfiddle.net/szrjt6ta/10/

jQuery - undefined function call on click

I want to call a function on the click event, my collegue defined the function as written below. Somehow I cannot access it, what is wrong?
function Start(data) {
this.move= function() {
....
};
$('.button').click(function(){
this.move();
});
}
this in a click function is the clicked element. Save a reference of the object in a variable outside the function and use it :
function Start(data) {
var self = this; //HERE
this.move= function() {
....
};
$('.button').click(function(){
self.move();
});
}
Here's an article that may give you more explanation about the above fix.
try this, you must remember reference to your main function.
function Start(data) {
var that = this;
this.move = function() {
....
};
$('.button').click(function(){
that.move();
});
}
Another way to keep the scope is to use jQuery's proxy()
$('.button').click($.proxy(this.move, this));
In an event handler bound with jQuery, this refers to the DOM element on which the handler was bound. See jQuery Event Basics.
You can override jQuery's this binding by using function#bind on the click handler:
function Start(data) {
this.move= function() {
....
};
$('.button').click(function(){
this.move();
}.bind(this));
}
Beware of browser support for function#bind -- if you target older browsers you'd need a polyfill or simply assign the value of this to another variable.

Object method as callback function [duplicate]

I have a bunch of handlers that call up a specific jQuery plugin. I would like to refactor the code and create an object whose properties and methods can be passed to a wrapper which would then call up the plugin.
Problem: I have difficulties emulating the following statement:
$("li", opts.tgt).live("click", function () { GetContact(this); });
Does someone have some suggestions on how to proceed? TIA.
function InitAutoCompleteTest() { // Init custom autocomplete search
var opts = {
tgt: "#lstSug", crit: "#selCrit", prfxID: "sg_", urlSrv: gSvcUrl + "SrchForContact",
fnTest: function (str) { alert(str) },
fnGetData: function (el) { GetContact(el) }
}
$("input", "#divSrchContact").bind({
"keypress": function (e) { // Block CR (keypress fires before keyup.)
if (e.keyCode == 13) { e.preventDefault(); };
},
"keyup": function (e) { // Add suggestion list matching search pattern.
opts.el = this; $(this).msautocomplete(opts); e.preventDefault();
},
"dblclick": function (e) { // Clear search pattern.
$(this).val("");
}
});
opts.fnTest("Test"); // Works. Substituting the object method as shown works.
// Emulation attempts of below statement with object method fail:
// $("li", opts.tgt).live("click", function () { GetContact(this); });
$("li", opts.tgt).live({ "click": opts.fnGetData(this) }); // Hangs.
$("li", opts.tgt).live({ "click": opts.fnGetData }); // Calls up GetContact(el) but el.id in GetContact(el) is undefined
}
function GetContact(el) {
// Fired by clicking on #lstSug li. Extract from selected li and call web srv.
if (!el) { return };
var contID = el.id, info = $(el).text();
...
return false;
}
Edit
Thanks for the feedback. I finally used the variant proposed by Thiefmaster. I just wonder why the method must be embedded within an anonymous fn, since "opts.fnTest("Test");" works straight out of the box, so to speak.
$("li", opts.tgt).live({ "click": function () { opts.fnGetData(this); } });
Simply wrap them in an anonymous function:
function() {
opts.fnGetData();
}
Another option that requires a modern JS engine would be using .bind():
opts.fnGetData.bind(opts)
Full examples:
$("li", opts.tgt).live({ "click": opts.fnGetData.bind(opts) });
$("li", opts.tgt).live({ "click": function() { opts.fnGetData(); }});
Inside the callback you then use this to access the object.
If you want to pass the element as an argument, you can do it like this:
$("li", opts.tgt).live({ "click": function() { opts.fnGetData(this); }});
From documentation
.live( events, data, handler(eventObject) )
eventsA string containing a JavaScript event type, such as "click" or "keydown." As of jQuery 1.4 the string can contain multiple, space-separated event types or custom event names.
data A map of data that will be passed to the event handler.
handler(eventObject) A function to execute at the time the event is triggered.
Example:
$('#id').live('click', {"myValue":"someValue"}, function(evt){
console.log(evt.data["myValue"]); // someValue
});​
JQuery live

Javascript: How to pass an argument to a method being called without parentheses

Sorry for how stupid this is going to sound. My JS vocabulary is terrible and I had absolutely no idea what to search for.
I'm using jQuery.
So I've got this code:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(example.open);
}
};
$(document).ready(function(){example.init();)
So here's the problem: I want to pass an argument to example.open() when I click the "a" element. It doesn't seem like I can, though. In order for the example.open method to just…exist on page-load and not just run, it can't have parentheses. I think. So there's no way to pass it an argument.
So I guess my question is…how do you pass an argument to a function that can't have parentheses?
Thanks so much.
Insert another anonymous function:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(function()
{
example.open($(this));
});
}
};
You can also try this version because jQuery set the function's context (this) to the DOM element:
var example = {
open: function(){
alert($(this).text());
},
init: function(){
$("button").click(example.open);
}
};
Since jQuery binds the HTML element that raised the event into the this variable, you just have to pass it as a regular parameter:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(function() {
// jQuery binds "this" to the element that initiated the event
example.open(this);
});
}
}
$(document).ready(function(){example.init();)
You can pass the anchor through its own handler:
var example = {
open: function( element ){
alert(element.text());
},
init: function(){
$("a").on("click", function() {
example.open( $(this) );
});
}
};
$(document).ready(function() {
example.init();
});
I don't understand what you actually want to do;
however, I can give a try:
var example = {
open: function(event){
event.preventDefault();
alert($(event.target).text()+' : '+event.data.x);
},
init: function(){
$("a").bind('click',{x:10},example.open);
}
};
$(example.init);
demo:
http://jsfiddle.net/rahen/EM2g9/2/
Sorry, I misunderstood the question.
There are several ways to handle this:
Wrap the call in a function:
$('a').click( function(){ example.open( $(this) ) } );
Where $(this) can be replaced by your argument list
Call a different event creator function, which takes the arguments as a parameter:
$('a').bind( 'click', {yourvariable:yourvalue}, example.open );
Where open takes a parameter called event and you can access your variable through the event.data (in the above it'd be event.data.yourvariable)
Errors and Other Info
However your element.text() won't just work unless element is a jQuery object. So you can jQueryify the object before passing it to the function, or after it's received by the function:
jQuery the passed object:
function(){ example.open(this) } /* to */ function(){ example.open($(this)) }
jQuery the received object:
alert(element.text()); /* to */ alert($(element).text());
That said, when calling an object without parameters this will refer to the object in scope (that generated the event). So, really, if you don't need to pass extra parameters you can get away with something like:
var example = {
open: function(){ // no argument needed
alert($(this).text()); // this points to element being clicked
},
init: function(){
$("a").click(example.open);
}
};
$(document).ready(function(){
example.init();
}); // your ready function was missing closing brace '}'

jQuery: UI widget definition

I have a widget defined like so:
$.widget("ui.mywidget", {
_init: function() {
this.element.bind("keyup", function(event) {
alert(this.options);
alert(this.options.timeout);
});
}
});
And trying to call it like so:
$("input.mywidget").mywidget({timeout: 5});
I also redefined the bind method using the this.element.keyup(function(event) { ... }) style: no difference.
But, in the keyup bind, this.options (and referencing it just as options) both yield undefined. I thought the UI widget framework allowed this type of abstraction; am I doing something wrong?
When inside bind(), this changes to refer to the object that the event is raised on. Try:
$.widget("ui.mywidget", {
_init: function(options) {
var opts = this.options;
this.element.bind("keyup", function(event) {
alert(opts);
alert(opts.timeout);
});
}
});
What #Dave said is right. You can also set "this" to a variable rather than using options as an argument to the init function. Here is how I see it implemented often:
$.widget("ui.mywidget", {
options: {
timeout: 100
},
_init: function() {
var self = this;
self.element.bind("keyup", function(event) {
alert(self.options);
alert(self.options.timeout);
});
}
});
Why stop there? Check out $.proxy and write better code
$.widget("ui.mywidget", {
_create: function() {
//Under this syntax, _omgAlertsRule must be a method of 'this'
this.element.bind("keyup", $.proxy( this, '_omgAlertsRule' ) );
},
_omgAlertsRule: function( event ){
alert(this.options);
alert(this.options.timeout);
}
});

Categories

Resources