Execute Jquery every time a specific function runs [duplicate] - javascript

This question already has answers here:
do something when function executes Jquery
(2 answers)
Closed 9 years ago.
Is it possible to execute something every time a specific function runs without any knowledge about that function besides its name?
This would be similar to bind
var clicked = 0;
$('#foo').bind('click',function(){
clicked += 1;
alert(clicked);
});
So there, every time something with the ID foo is clicked, it will add 1 to the variable clicked so that I know how many times it has been clicked. What I want to do would be the equivalent of the following if it were correct syntax:
var fired = 0;
$('my_function').bind('run',function(){
fired += 1;
alert(fired);
});
I don't care if in any given situation you would be in, you would always be able to figure something out about the function and use that, I don't want work arounds, this is what I want for an answer:
How I can execute something everytime a specific function runs, just given the name of the function. If that is not possible, why not?

Try something like this:
var temp = my_function, fired = 0;
my_function = function() {
fired++;
temp.apply(this,arguments);
}

I think something like this may be the closest you can come:
function adjustFunctionToCount(f){
var count = 0;
function newF(){
count++;
f.apply(this, arguments);
}
newF.getCount = function(){ return count; };
return newF;
}
And so if you have
function handler(val){
console.log('called with val ' + val);
}
You could do
handler = adjustFunctionToCount(handler);
handler('a');
handler('b');
console.log(handler.getCount());
FIDDLE
And needless to say you could create your function inline
var handler = adjustFunctionToCount(function(val){ console.log('called with val ' + val); });
handler('a');
handler('b');
console.log(handler.getCount());
UPDATED FIDDLE

I'm pretty sure that's impossible in the general case.
Remember, functions are objects, really, and the name of a function is just a variable. Functions can exist without being assigned to a named variable, the variables can be out of your scope, or reassigned/swapped around. In any case, I know of no API that lets you hook onto a JS function call.
This may be of interest: Can I intercept a function called directly?

This is where event driven programming comes in - and jQuery makes it really easy to do.
var myFunction = function() {
//...
//...
//...
$(document).trigger('someEvent');
}
$(document).on('someEvent',function() {
//the function you would like to run every time myFunction is called
});

Try this:
var count = (function(){
var c = 0;
return function(){
alert(c++);
};
})();
$('#foo').click(count);
OR
$('#foo').bind('click', count);
When an Anonymous Function or a Variable that represents a Function is passed it is the same thing. You could make your own code that executes a Function like this:
function executeFun(func){
return func();
}
executeFun(count)
executeFun(function(){
/*everything happens in here. The Anonymous Function will be called
automatically because of the parameter next to the variable func above */
})
Although, that example is impractical it shows you what happens internally. Also, I solved your potential global scope variable problem with a Closure. For more on Closures visit https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures .

Related

Newbie - Manipulating closures and For Loops

The answer to why this code is not working is because: The problem with this method is is you're not providing a function as the second argument. You're calling a function - that function is making things blue. It's not returning a function that is making things blue. So you're making things blue immediately and, when the click happens, there's nothing to call, because the function you called returned nothing.
But I'm lost after the first sentence. could someone dumb this down? perhaps a visual explanation of the code would help!
Code: https://jsfiddle.net/2yfj89af/1/
var submitSOBox = document.getElementsByClassName("submitSOBox");
for (i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', SOBoxColor(i));
}
function SOBoxColor(i) {
submitSOBox[i].style.backgroundColor = "blue";
}
The reason explained: you have this line:
submitSOBox[i].addEventListener('click', SOBoxColor(i));
This calls addEventListener which expects a function as the last argument. You provide SOBoxColor(i), which is not a function, but a value returned by a function -- you call it. To pass a function, you would need to pass something like SOBoxColor, so without calling it. This is needed because your browser needs to know what to call when the click event happens.
Now, passing just SOBoxColor will not do what you want. Yes, it will make that SOBoxColor gets called when a click happens, but you will not have the i value passed to it.
To achieve that, you need a modified version of your function that somehow has the i value pre-filled as argument. Luckily there is a way to create such a modified function with the bind method, which returns the same function, but with some things bound to it:
submitSOBox[i].addEventListener('click', SOBoxColor.bind(submitSOBox[i], i));
The first argument of bind determines what the special this object will represent when SOBoxColor is called, and the second argument is what i will be.
Now, this will work.
But you can do it even nicer if you would use the this keyword in your SOBoxColor function, because then you don't even need the i parameter:
function SOBoxColor() {
this.style.backgroundColor = "blue";
}
... and your binding can also do without the i argument:
submitSOBox[i].addEventListener('click', SOBoxColor.bind(submitSOBox[i]));
It can still be done more concisely, because when the click happens, the browser will already provide a nice service to us: it sets the this keyword to the element to which you added the event handler, so in the end it is not even necessary to bind submitSOBox[i] to it explicitly. This will work also:
submitSOBox[i].addEventListener('click', SOBoxColor);
... provided you changed the SOBoxColor function to work with this.
When you add the event listener like you are:
submitSOBox[i].addEventListener('click', SOBoxColor(i));
It is calling the function SOBoxColor(), expecting it to return a function that will be called when the event listener is triggered.
By return a function, I mean like this:
function SOBoxColor(){
return function(){
alert("hello")
//Do stuff
}
}
If you replaced the current function with the one above, it would alert "hello" whenever the click listener is triggered.
How would you fix this?
Simply put the functions name in it, without calling it:
submitSOBox[i].addEventListener('click', SOBoxColor);
The problem you are going to have now is, with your current function, SOBoxColor:
function SOBoxColor(i) {
submitSOBox[i].style.backgroundColor = "blue";
}
You are sending the number as a parameter to select the appropriate element, which you can't do anymore.
However, this isn't a problem, since you were selecting the element incorrectly in the first place.
Instead of selecting it with it's index in the HTMLCollection submitSOBox, just reference the current element with the this keyword:
function SOBoxColor() {
this.style.backgroundColor = "blue";
}
So, your complete code should now look like:
var submitSOBox = document.getElementsByClassName("submitSOBox");
for (var i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', SOBoxColor);
}
function SOBoxColor() {
this.style.backgroundColor = "blue";
}
You're assuming calling a function must be done by
functionName();
But it's not the only way of calling functions. You could input a function as an argument, use the call method: functionName.call(null,args), etc.
What functionName(); does is make Javascript go, "Hey, I need to find out what that function returns." So if functionName is like
function functionName(){
console.log("hello!");
return undefined;
};
Javascript will try to simplify everything. It will run through your function, console log "hello!" while it's busy working, and in the very end figure out what your function returns:
undefined;
Think of it like simplifying math expressions back in algebra class or something.
In your case, you're telling the click event to call whatever is returned by SOBoxColor(i). So if SOBoxColor looked like this:
function SOBoxColor(i) {
submitSOBox[i].style.backgroundColor = "blue";
return 9000;
}
Your click event would look like this:
for (i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', 9000);
}
addEventListener is a function that wants a function as the 2nd argument, not a number. so nothing would happen.
As you are said the function returns nothing. in fact it is not a function at all. The idea of closure is to return function which uses values in outer scope.
var submitSOBox = document.getElementsByClassName("submitSOBox");
for (i = 0; i < submitSOBox.length; i++) {
//changes are possible here but we'll do it later
submitSOBox[i].addEventListener('click', SOBoxColor(i));
//in your initial code SOBoxColor(i) returned undefined (no return)
//and event listener must be a function. Yours was not.
}
//change your function like this:
function SOBoxColor(i) {
//get the element from collection.
//both collection and i are available at this point
var elem = submitSOBox[i];
return function(){
//function knows elem from parent scope
elem.style.backgroundColor = "blue";
};
}
I hope this explanations are helpful.
Extra
This is an exercise with closure. If it were not then it would be simpler solution:
var submitSOBox = document.getElementsByClassName("submitSOBox");
for (i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', function(){
this.style.backgroundColor = "blue";
//in this context **this** is clicked element
});
}
Basically
submitSOBox[i].addEventListener('click', SOBoxColor(i));
He is excecuting the function SOBoxColor with the current value of i as argument.
Also when when you add an event listener to an element, you have already the implicit value of this pointing at the DOM element. So just the change the code:
function SOBoxColor() {
this.style.backgroundColor = "blue";
}
var submitSOBox = document.getElementsByClassName("submitSOBox");
for (i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', SOBoxColor);//your passing the function
}
Also it's all more simple very simple with jQuery:
$(".submitSOBox").click(function(){ $(this).css("background-color","blue"); });

A Javascript event listener's anonymous function keeps returning the same value? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 months ago.
I was writing a code that basically adds event listeners that call a function with the a fragment of their dom object's id, but every time I click an object with the listener It just gives me the same value no matter what object I click. Here's my code:
//add events
for (a=0; a<=tab_array.length-3; a++)
{
alert(a);
document.getElementById("mini_"+a).addEventListener("click",function(){open_tab(a)},false);
}
function open_tab(e)
{
//change across settings ect
alert("tab "+e+" clicked");
}
I realize it probably has something to do with pointers and that fact its using an anonymous function instead of directing passing a, but I just don't know what to do instead.
Your guess is correct. The behavior you see is because of your scope.
When your link is clicked javascript is passing the current value of a.
This value is tab_array.length-2 instead of the value a had during the loop run 0, 1 ....
To keep the value of a you have to create a new variable in a new scope (closure). E.g. e:
for (a=0; a<=tab_array.length-3; a++)
{
function(e){
document.getElementById("mini_"+e).addEventListener("click",function(){open_tab(e)},false);
}(a));
}
Another way would be to write a function which returns your handler inside its own scope:
//add events
for (a=0; a<=tab_array.length-3; a++)
{
alert(a);
document.getElementById("mini_"+a).addEventListener("click", open_tab(a) ,false);
}
function open_tab(e) {
return function() {
//change across settings ect
alert("tab "+e+" clicked");
}
}
See my fiddle or the Closure guide
Both of #jantimon's code samples are fine ways to solve this problem, but I'd like to suggest a third approach. Instead of a self-calling function expression or a function that returns a function, consider an ordinary named function:
for( var i = 0; i <= tab_array.length - 3; ++i ) {
setupTab( i );
}
function setupTab( i ) {
var element = document.getElementById( 'mini_' + i );
element.addEventListener( 'click', function() {
open_tab( i );
});
}
This is essentially the same code as the self-calling function, but with these advantages:
Familiarity. It's just an ordinary function call.
Shorter and simpler loop body.
With the self-calling function, the function parameter and the actual argument passed in are at opposite ends of the function (parameter at the beginning, argument at the end). A separate function avoids that.
These are just minor advantages, to be sure—any of these approaches will do the trick. But I do like the clarity of this method.

Extra parentheses on function [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What do parentheses surrounding a JavaScript object/function/class declaration mean?
What does this “(function(){});”, a function inside brackets, mean in javascript?
A Javascript function
I encountered markup similar to this:
var something = (function(){
//do stuff
return stuff;
})()
document.ondblclick = function(e) { alert(something(e)) };
I don't understand the opening ( and closing )() in the something variable.
Could you explain the difference to writing it like this?
var something = function(){
//do stuff
return stuff;
};
Thanks!
It's probably easier to understand if you leave the redundant parens out because they serve no purpose:
var something = function() {
return 3;
} // <-- a function.
(); // now invoke it and the result is 3 (because the return value is 3) assigned to variable called something
console.log(something) //3 because the function returned 3
var something = function() {
return 3;
}; // a function is assigned to a variable called something
console.log(something) //logs the function body because it was assigned to a function
console.log(something()) //invoke the function assigned to something, resulting in 3 being logged to the console because that's what the function returns
(function(){ ... }) is a (anonymous) function expression, you could e.g. assign that value to a variable.
The brackets behind it will immidiately execute the function expression, resulting in the return value of the function (in here: stuff). The construct is called IIFE.
When stuff is a function (which I assume, because you invoke something lateron), this is called a closure - the returned function (stuff, assigned to something) still has access to the variables in the execution context of that anonymous function.
On the question what it does, read all the comments and other answers. They are absolutely right.
Why would you want to use it? You find this pattern very often when using closures. The intent of the following code snippet is to add an event handler to 10 different DOM elements and each one should alert it’s ID attribute (e.g. “You’ve clicked 3″). You should know that if this was your actual intent, then there is a much easier way to do this, but for academic reasons let’s stick with this implementation.
var unorderedList = $( "ul" );
for (var i = 0; i < 10; i++) {
$("<li />", {
id: i,
text: "Link " + i,
click: function() {
console.log("You've clicked " + i);
}
}).appendTo( unorderedList );
}
The output of the above code may not be what you first expect. The result of every click handler will be “You’ve clicked 9″ because the value of i at the point the event handler was fired is “9″. What the developer really wanted is for the value of i to be displayed at the point in time the event handler was defined.
In order to fix the above bug we can introduce a closure.
var unorderedList = $( "ul" ), i;
for (i = 0; i < 10; i++) {
$("<li />", {
id: i,
text: "Link " + i,
click: function(index) {
return function() {
console.log("You've clicked " + index);
}
}(i)
}).appendTo( unorderedList );
}
You can execute and modify the above code from jsFiddle.
One way to fix the above code is to utilize a self-executing anonymous function. That is a fancy term that means we are going to create a nameless function and then immediately call it. The value of this technique is that the scope of the variable stays within the function. So, first we will surround the event handler content in a function and then immediately call the function and pass in the value of i. By doing that, when the event handler is triggered it will contain the value of i that existed when the event handler was defined.
Further reading on closures: Use Cases for JavaScript Closures
All of the answers were good, but I think the simplest answer has been skimmed over:
var something = (function(){
//do stuff
return stuff;
})()
After this code executes, something becomes stuff. The function that returned stuff is executed before something is assigned.
var something = function(){
//do stuff
return stuff;
};
After this code executes, something is a function which returns stuff. The function that returns stuff was never executed.
Check the JavaScript FAQ section, too: Here are some pretty good explanations and examples
Ok, why should you use this:
Suppose my script is running, and there are a couple of things (I'm, for instance, looping through a nodes list) I might be needing later on. That's why I might choose to do something like this:
for(var i=0;i<nodesList.lenght;i++)
{
if (nodesList[i].id==="theOneINeed")
{
aClosure = (function(node,indexInNodesList)//assign here
{
return function()
{
node.style.display = 'none';//usable after the parent function returns
alert(indexInNodesList+ ' is now invisible');
}
})(nodesList[i],i);//pass the element and its index as arguments here
break;
}
}
i = 99999;
aClosure();//no arguments, but it'll still work, and say i was 15, even though I've just
//assigned another value to i, it'll alert '15 is now invisible'
What this enables me to do is to prevent function arguments from being garbage collected. Normally, after a function returns, all its var's and arguments are GC'd. But in this case, the function returned another function that has a link to those arguments (it needs them), so they're not GC'ed for as long as aClosure exists.
As I said in my comment. Google closures, practice a bit, and it'll dawn on you... they really are quite powerful

() right after a function means the function is going to get fired immediately? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What do empty parentheses () after a function declaration do in javascript?
I am looking at some Javascript code and trying to figure out what }(); right after return num+10 means. Does that mean the function will get executed immediately? Where can I get more information about this.
function addToTen(num) {
return function() {
return num+10;
}();
}
addToTen(5); // 15
Thanks,
Venn.
Yes, but only if it's a function expression, which is different from a function declaration. A function declaration is how your first function is defined:
function foo(){
}
If you add () after this, you get a Syntax Error. If the function is defined as a function expression, adding a set of parenthesis immediately executes it. Functions are expressions whenever they are not defined as above, e.g.:
(function(){}());
var x = function(){}();
return function(){}();
Your actual example is just... odd, and pointless. It's almost a classic closure example, something like:
function addTo(x){
return function(y){
return x + y;
}
}
var addToTen = addTo(10);
addToTen(5); // 15;
but your actual example is equivalent to just:
function addToTen(num){
return num + 10;
}
and all the extra stuff is completely unnecessary.
Yes, it means the function object is evaluated.
Just like with any other function, you have two ways of looking at it:
var myFunction = function(val) {
return val + 1;
}
To return the function object, or send it somewhere else, I just say myFunction
If I wish to execute it, I say myFunction()
In this closure or decorator, whatever, that you've described above, rather than return the function object itself, you're returning the value of executing that function immediately, hence the () afterwards.
Yes, it's executed immediately, but the usage doesn't make any sense in this example.
Often used for anonymous functions creating a closure.
see Why do you need to invoke an anonymous function on the same line?
One place where I use it a lot:
(function($) {
// secure way to ensure no conflict between $ (jQuery)
// and another js-framework can happen
$...
})(jQuery);

JavaScript: Is it possible to pass a variable into a callback function that is assigned to a variable?

A lot of people say that this is asked too much in the comments, which made me hesitant to ask this, but I still have not found a solution in their answers, mostly because (1) they are typically using jQuery and (2) the questions usually contain technicalities I do not understand.
I have a function with a variable inside. The variable is assigned a function. I'm sure this concept is not exclusive to AJAX, but that is the context I am using it in, if it makes a difference.
function iClick(this)
{
var foo = "I would like to pass this.";
ajax.onreadystatechange = function (foo) { alert(foo); }
}
I want to pass a variable into the function. However, since there is no original function declaration, how do I specify parameters? Can I even do that?
Just don't declare that variable as a parameter in your anonymous function, like this:
function iClick(this)
{
var foo = "I would like to pass this.";
ajax.onreadystatechange = function () { alert(foo); }
}
When you call the first parameter foo it's whatever's calling that callback passes in that's foo inside the function. If you want to reference a previously declared variable just do that, make sure not to use a parameter with the same name.
You can create a function like this
var c="hello";
(function(b){
alert(b)
})(c);
result would be "hello"
You can also do this, but maybe it's not necessary:
function iClick(this)
{
var foo = "I would like to pass this.";
ajax.onreadystatechange = (function(thevar) {
return function () { alert(thevar); };
})(foo);
}
As #John Hartsock referred, the answer that everyone should really remember is this
var c="hello";
(function(b){
alert(b)
})(c);
And that's very important for example in a for loop when there is some async function inside it, because otherwise you don't get the correct item.
Tell me, what comes out from here?
for (var i=0; i<5; i++){
setTimeout(function(){
console.log(i);
}, 1000);
}
Exactly: all 5, because when all the timers are triggered after 1 second, variable i is already at the value 5.
But if you use a self-invoked anonymous function (SIAF) like this
for (var i=0; i<5; i++){
(function (j){
setTimeout(function(){
console.log(j);
}, 1000);
})(i);
}
it does work, since every time the function is evoked, it runs another instance of the function and as any function, it has its own local variables. I do not merely define the function, I also run it right away (through the (); at the end), but then internally a new instance of the function will be created with different internal local variables, as I parse to the function a different variable every time I run it.
I belive you wanted something like that
function handleAjaxRequest(params) {
var context = {'b':'inner', 'c': params['c']};
function rendered(html) {
// render
}
function gotPart(part) {
context['a'] = part;
engine.render(context).addCallback(rendered);
}
ajax.getPart(params).addCallback(gotPart);
}

Categories

Resources