Wrapping a function which uses $(this) - javascript

I'm working on some code which uses jQuery Countdown plugin. The plugin allows for a callback function to be passed which will be executed when the countdown hits zero:
{
until: new Date(remaining),
onExpiry: runSomeAction
}
runSomeAction uses $(this) to pick up the timer which hit zero. I'd like to wrap runSomeAction but the only way I know how to do this is to add a paramenter to it, like this:
{
until: new Date(remaining),
onExpiry: function() {
// my logic here...
runSomeAction($(this));
}
}
But now I have to change all $(this) references in runSomeAction to the parameter name.
Is there a way to wrap runSomeAction so that it can continue using $(this) and I don't have to change it?

You can use the call or apply javascript functions to change the this context for a given function. Something like this should work for you:
onExpiry: function() {
// my logic here...
runSomeAction.call($(this));
}
Now within the runSomeAction function, this will equal $(this) from the point the function was called.

I am not exactly clear what you are after. More code would have cleared up my answer.
You should be able to use jQuery's .proxy( function, context ) method.
Depending on what this scope you are after, it would either be
onExpiry: $.proxy(runSomeAction,this)
or
onExpiry: function() { runSomeAction.call(this); }
You could change it to $(this) in the proxy if you want the jQuery object.

Related

jQuery which is the correct function definitions?

I saw three different function definitions in jQuery. What is the correct way to use them?
Example 1:
function example() {
// code here
}
Example 2:
jQuery('#Example').click(function() {
// code here
});
Example 3:
var example = {
demo : function() {
// code here
}
}
Why should I choose which?
There is no 'best' here, as each function definition is separate and serves different purposes. Also note that only the second example has anything to do with jQuery.
Your first example is just a vanilla JS function definition, nothing special about this.
Your second is a jQuery click event handler which is used to declare logic which should be executed when the click event occurs on the selected element.
The third example is a function definition inside an object, which can be useful when using an OOP approach (as if to declare a class/model), or just passing a collection of values around in your logic.
Example 1 and 3 have nothing to do with jQuery. These are vanilla javascript snippets.
On example 2, it's recommended to use this syntax instead :
jQuery('#example_container').on('click', '#Example', function(event) {
// code here
});
This lets you delegate the event handling, which means even if you created that element after the page was loaded, the event will still be handled.
Your first example:
function example() {
// code here
}
Is the way to define a function and it is going to be available depending on its scope.
The second example:
jQuery('#Example').click(function() {
// code here
});
You are not only defining a Function but you are adding this function into the click event for a html element that has the id "Example"
The third Example:
var example = {
demo : function() {
// code here
}
}
You are defining a function inside an Object. So this function is going to be the method "demo" of the object "example" you just created.

Using $(this) & event in named handler function

I have this function:
function showPost(event){
event.preventDefault();
$(this).parent('article').animate({width:'100%'}, 'slow');
}
I am attempting to use it like so:
$('.article-header').click(function(event){showPost(event);});
When I use it in the above manner, the event property is passed just fine, however $(this) doesn't work within the function. If I attempt to include this as a parameter in the .click method, it returns an error claiming this is undefined. I have even gone so far as to set var ths = $(this); to no avail.
Please, what is the proper way to make this function happen?
Just use the function directly:
$('.article-header').click(showPost);
You're loosing this because you're calling the function "naked", with no object receiver. You could do this too (but don't because there's no point here):
$('.article-header').click(function(event) { showPost.call(this, event); });

Calling jQuery document.ready functions by hand

If I make an AJAX request and want to call all functions that were set up by $(document).ready(). How can I do it? Thank you
$(document).ready();
If that doesn't work, try this:
function startup() {
// All your functions in here.
}
$(document).ready(startup);
And after your AJAX request is finished:
startup();
The easiest way is to use a shared function:
$(document).ready(function() {
setup();
});
$.post('/', {}, function() {
setup();
}, 'json');
But if you're using it to re-assign listeners, you would probably be able to get away with assigning them before they're created, like this:
$(document).ready(function() {
$(document).delegate('.my-button', 'click', function() { });
});
Using this code, all .my-button clicks will be handled by your custom function, regardless of whether the button existed in your DOM upon DOMReady.
Note that:
$(document).ready(function() { ... }); can be minimized to $(function() { ... });
If you're using jQuery 1.7+, prefer .on over .delegate: $(document).on('click', .my-button', function() { });
Prefer narrower context over broader, i.e. $('#close-parent').delegate over $(document).delegate
Instead of triggering document.ready by hand (which would be bad practice IMHO), make a function that's called setup which sets up all listeners etc. and invoke this function when you need to re-apply things etc.

How can I detect when a function is called as a jQuery callback vs. called directly?

I'm using hoverIntent which, as part of its settings, will call a function. I think this is called 'referencing a function' (correct?):
var HIconfig = {
interval: 250,
sensitivity: 8,
over: myFunction,
timeout: 100,
out: myOtherFunction
};
However, I'd like to reuse said function at times and explicitly pass in a jQuery object. So, I added that to the function.
myFunction($myObject){
}
The challenge now is to figure out when the function is being referenced by hoverIntent or being explicitly called. My thought was that I'd check to see if $(this) contained a particular DOM element:
myFunction($myObject){
if($(this).is('li')){
$myObject = $(this)
};
$myObject.doSomething...
}
But...I'm having issues. If I log out both $(this) and $myObject these are the results:
Called via hoverIntent:
$(this) = [li#Trigger-0.nav-main-tab]
$myObject = Object { originalEvent=, more...}
Called via explicitely passing an object
$(this) = [Window PT02-home-page.php#]
$myObject = [li#Trigger-0.nav-main-tab]
I can test for $(this).is('li') in the first scenario, as it's true.
I can't in the second, though, as when I try to perform the test, Firefox doesn't like it:
g.nodeName is undefined
One suggestion was to switch to 1.4.1 and try to test for the opposite via .isPlayObject:
if (jQuery.isPlainObject($myObject))...
This works just fine in Firefox. However, IE8 always returns true.
My questions:
Is my logic simply way off in terms of how my function gets called from hoverIntent vs. directly?
If not, is there a way to consistently test to see if I have explicitly passed in an object to my variable in the function?
I would do this totally differently. First, it's weird to have a function take a jQuery object as a parameter. Go the jQuery way and make your function into a jQuery plugin. For use in your hoverIntent configuration, you can either wrap your function in another little function, or do that with the new (1.4) jQuery.proxy() function.
Instead of passing an object, why not pass a simple boolean to indicate where it has been called from, for instance:
myFunction(asOption){
if(asOption) {
alert("called from hoverIntent");
} else {
alert("called from somewhere else");
}
}
or am I completely missing the point?
You're making this unnecessarily complex. Just use a wrapper for the callback that passes the argument the function expects:
var HIconfig = {
interval: 250,
sensitivity: 8,
// myFunction expects a jQuery object, so create one from the context
over: function() { myFunction($(this)) },
timeout: 100,
out: myOtherFunction
};
...then you can skip the check inside your function altogether:
myFunction($myObject)
{
$myObject.doSomething...
}

Inline functions and other method's scope

How do I make the myFunction visibile for the in-line function in .ready() event?
$(document).ready(function() {
...stuffs...
myFunction(par1, par2, anotherFucntion_callback);
}
);
function anotherFunction_callback(data) {
..stuffs..
}
I didn't quite catch your question. Do you mean that you want to pass "myFunction_callback(data)" as the last argument in your:
myFunction(par1, par2, anotherFunction_callback);
, including that "data" parameter?
In that case the solution is pretty standard, write this before that one:
var temp = function() { anotherFunction_callback(data) };
an alternative syntax is:
function temp() { myFunction_callback(data) };
// even though this looks just like a free function,
// you still define it inside the ready(function())
// that's why I call it "alternative". They are equivalent.
In general, if you want to pass a function with 1 or more arguments to another function, you use that format. Here, we basically create a new no-argument function that calls another. The new function has access to the "data" variable. It's called "closure", you may want to read more on that.
Of course, if the callback require no argument, you can just use the original function name.
I hope this helps.
ps: You can even inline the function declaration, making it anonymous, like so:
myFunction(par1, par2, function() { myFunction_callback(data) });
Notice that the
$(document).ready(function() {});
looks pretty much just like that.
You use the actual name of the function, i.e. myFunction_callback instead of myFunction or anotherFucntion_callback.

Categories

Resources