JQuery named functions with scope - javascript

I need to execute a single function on a set of adjacent DIVS on my page. I thought it would work best like this:
function namedFunction(){
setTimeout(3000);
//do animations and such
$(this).next().call(namedFunction);
}
$("#firstdiv").call(namedFunction());
but I can't find a way to arbitrarily execute a function in a set scope (the firstdiv object), and moreover I'm not even sure if the scope will be passed correctly. Is there a way to do this, or a better way to do this?

I guess you want this:
function namedFunction () {
this.animate({ ... }, function () {
namedFunction.call( $( this ).next() );
});
}
and then:
namedFunction.call( $('#firstdiv') );

The setTimeout() function doesn't pause the current execution, it queues a future execution of a function that you supply. To do something when the page loads use a document ready handler.
I think you want something like this:
$(document).ready(function() {
var $divs = $("div.commonClass"),
i = 0;
function processNextDiv() {
namedFunction($divs.eq(i));
i = (i + 1) % $divs.length;
setTimeout(processNextDiv, 3000);
}
processNextDiv();
});
This first selects all the divs (I'd suggest doing so by giving them a common class, but you can do that any way you like), then sets up a timeout based loop that calls namedFunction() passing it the current div to be processed. So then you could have:
function namedFunction($div) {
$div.animate(...); // process current div
}
Or you could put the animation or other div processing code directly in that processNextDiv() function, depending on whether you want to be able to call namedFunction() from other places.
Demo: http://jsfiddle.net/hWLTb/

Maybe this?
$("#firstdiv").nextAll("div").andSelf().each(function(){
// this = DIV
});

Related

addEventListener not working correctly

So I have a div which has an EventListener on it which works fine. But I want the EventListener to only be triggered at certain points, which is why I added an if statement to it.
I was under the impression that you can change global variables from functions the way my code is below yet this doesn't seem to work at all. I have tried changing the variable within the function by way of window.clickDisable = false; but that does not work either. The relevant parts of the code are below, does anybody know why this is not working? Thanks.
var clickDisable = true;
if (clickDisable == false) {
document.getElementById("fight")
var fightMenu = fight.addEventListener("click", fightMenuFunction)
}
function fightMenuFunction () {
}
setTimeout(introAnimation, 7000)
function introAnimation() {
clickDisable = false;
}
There are a handful of problems with your code:
I think the best approach is to put your if statement within the body of the function. You want the body of your function to run only if the timer has elapsed, rather than the event to be bound only if the timer has elapsed.
Also, your document.getElementById was not being used. You were instead benefiting from the fact that element ids are automatically interpreted as global variables, which you can do, as I have done below, but is probably not a best practice.
var clickDisable = true;
function fightMenuFunction () {
if(!clickDisable){
console.log('This is the function running.')
}
}
fight.addEventListener("click", fightMenuFunction)
window.setTimeout(introAnimation, 7000)
function introAnimation() {
clickDisable = false;
}
<button id="fight">Fight</button>

How can I make variables so that I don't have to repeat myself in future functions

WARNING!! I AM A NOVICE THROUGH AND THROUGH
Alright, so I know there have been a lot questions about Global variables, and I think that's what I'm looking for, but, not exactly. Lately I've been needing to call upon the same lines of code several times. document.getElementById("example").style or similar to little things like that but I need to continuously repeat.
My question is how do I make it so that I make one variable, outside of the function, to save time writing these lines?
What I've been seeing is to simply write it outside like this var inferno = document.getElementById("inferno"); but this is far from working.
This is my code right now, it's simple because I was just using it as a test, but can anyone help me?
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
You have the right idea. Note, though, that the variable doesn't have to be global. It just has to be where all of the code that wants to use it can use it.
For example, this creates a global:
<script>
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
</script>
(Note that this needs to be after the markup creating the inferno element.)
The problem with globals is that they can conflict with each other, and in fact the global "namespace" is really, really crowded already.
You can avoid that by wrapping up the code that needs inferno in a scoping function, like this:
<script>
(function() {
var inferno = document.getElementById("inferno");
function infernoClick () {
inferno.style.backgroundColor="red";
}
function somethingElse () {
inferno.style.color="green";
}
})();
</script>
That code creates an anonymous function and then calls it immediately, running the code inside.
Now inferno is "global" to the functions that need it, but isn't actually a global.
Let's take a further example:
<script>
(function() {
var outer = 42;
function doSomethingCool() {
var inner = 67;
document.getElementById("someElement").onclick = function() {
alert("inner = " + inner + ", outer = " + outer);
};
}
// Can't use `inner` here, but can use `outer`
alert("outer = " + outer);
doSomethingCool();
})();
</script>
That code wraps everything in a scoping function, and the outer variable is accessible everywhere within that scoping function. It also has a function, doSomethingCool, which has a variable called inner. inner is only accessible within doSomethingCool. Look at what doSomethingCool does: It hooks up an event handler for when someElement is clicked. It doesn't call the function, it just hooks it up.
The really cool thing is that later, when someone clicks the element, that function has access to that inner variable.
And in fact, that's true for arguments you pass into the function as well. One last example:
<input type="button" id="element1" value="One">
<input type="button" id="element2" value="Two">
<script>
(function() {
function hookItUp(id, msg) {
document.getElementById(id).onclick = function() {
alert(msg);
};
}
hookItUp("element1", "This message is for element1");
hookItUp("element2", "And this one is for element2");
})();
</script>
There, we have this function that accepts a couple of arguments, and we call it twice: Once to hook up click on element1, and again to hook up click on element2.
The really cool thing here is that even though the clicks happen much later, after the calls to hookItUp have long-since returned, the functions created when we called hookItUp still have access to the arguments we passed to it — when we click element1, we get "This message is for element1", and when we click element2, we get "And this one is for element2."
These are called closures. You can read more about them on my blog: Closures are not complicated
That'll work, but only if the declaration appears after the point in the DOM where the element actually appears. Try moving your <script> to the very end of the <body>.
Another thing you can do is use the window "load" event to make sure the whole DOM has been seen before your code runs.
for example
var myGlobalVars = {"inferno":null,"othervar":null}; // globals in their own scope
function clickMe(varName,color) { // generic function
myGlobalVars[varName].style.backgroundColor=color;
}
window.onload=function() {
// initialise after the objects are available
for (var o in myGlobalVars) myGlobalVars[o]=document.getElementById(o);
// execute
clickMe("inferno","red");
}
.
.
T.J. Crowder gave a beautiful answer about scoping; just to add on that you can also use an immediately-invoked function expression to create a module with your UI elements, i.e.
var UI = (function() {
...
return {
inferno: document.getElementById("inferno");
};
})();
...
UI.inferno.style = ...;

Efficiency of nested functions inside of jQuery loops

What would be more efficient in terms of computer resources. Putting the event handler inside of a loop like this:
$('ul li').each(function()
{
$(this).mouseover(function()
{
// code to do something
});
Or having the function outside of the loop and creating a call to it inside the loop like this:
$('ul li').each(function()
{
$(this).mouseover(function()
{
doStuff($(this));
});
function doStuff(liElem)
{
// code to do something
}
It seems like to me that the second option would be easier on the computer because the code to do something wouldn't be repeated each time the loop iterates. Does the code of the event handler get created in the computer's memory every time through the loop, or is it just created once? Any thoughts?
There can be various optimizations possible but keeping it specific to the approach you have asked for,
please find the answer as inline comments in the code below
First approach:
$('ul li').each(function()
{
// Maybe you might like to declare some variables here
$(this).mouseover(function()
{
// code to do something
// Maybe you might like to use the variables declared in above function
// Disadvantage over other approach
// The code written here will need to store the context information of the outer function and global context
// Advantage over other approach
// You can directly access the variables declared in the above function
});
}
Or having the function outside of the loop and creating a call to it inside the loop like this:
Second approach:
$('ul li').each(function()
{
// Maybe you might like to declare some variables here
$(this).mouseover(function()
{
doStuff($(this));
});
});
function doStuff(liElem)
{
// code to do something
// Advantage over other approach
// The code written here will need to store the context information only for the global context
// Disadvantage over other approach
// You cannot directly access the variables declared in the outer function as you can in the other approach,
// you will need to pass them to the doStuff function to access here
}

Function timeout

I'm trying to write a code that adds a class to a div for a limited time, and then removes it.
I tried using javascript's setTimeout, and jQuery's delay, but nothing works.
The element is SET but never REMOVED.
Here's the come I came up with:
window.onload = function() {
$(".button").click(handler);
}
function handler() {
$(this).addClass("onclick");
setTimeout(function() { $(this).removeClass("onclick"); }, 3000); // JS's setTimeout
$(this).addClass("onclick").delay(3000).removeClass("onclick"); // jQuery's delay
}
I don't get what's wrong... I even tried writing a second handler for the setTimeout function.
Thanks in advanced.
The problem you're having is that this is different within the function you're passing to setTimeout than it is outside it. The usual fix is to use the closure by creating a variable to hold it, and using the variable instead:
function handler() {
var $elm = $(this);
$elm.addClass("onclick");
setTimeout(function() {
$elm.removeClass("onclick");
}, 3000);
}
There I've also use the var to cache the result of $(this) because there's no point in doing it more than once.
More background:
In JavaScript, unlike some languages that look similar, this is defined entirely by how a function is called. When you use setTimeout, the way the function gets called will make this be the global object (window, on browsers), so that's why $(this).removeClass(...) wasn't working.
More on this if you're interested:
Mythical methods
You must remember this
this inside the setTimeout call does not refer to the clicked element.
Change it to this:
function handler() {
var t = $(this);
t.addClass("onclick");
setTimeout(function() { t.removeClass("onclick"); }, 3000);
}
Working example - http://jsfiddle.net/5vakN/
Reference for how this works in javascript - http://bonsaiden.github.com/JavaScript-Garden/#function.this

How to define javascript event handlers dynamically with a function

I'm somewhat new to Javascript and I can't seem to figure out exactly what's going on with my functions.
Background: my script is supposed to let you assign a class of either "toggler" or "toggled" to an element to have them automatically linked, so checking/unchecking the toggler will show/hide the toggled (I know there are many libraries that can do this but unfortunately I can't use them in this case)
The script executes on pageload and searches through the elements for ones with the class "toggler" and then assigns its onclick handler accordingly. Here's the bit of code I'm having problems with:
function makeToggle () {
for (i=0;i<toggler.length;i++) {
toggler[i].onclick=function(){toggleSection(this,i)};
}
}
function toggleSection(obj,index) {
if (obj.checked==true) {
toggled[index].style.display="inline-block";
} else {
toggled[index].style.display="none";
}
}
"This" is passed correctly and resolves to whatever checkbox it's applied to, but "index" is always set to the length of the toggler array instead of being incremented. For example, the first and second togglers' onclick should be:
onclick="toggleSection(this,0)"
onclick="toggleSection(this,1)"
What they are actually set for (assuming I have 5 elements defined as a toggler) is:
onclick="toggleSection(this,5)"
onclick="toggleSection(this,5)"
From what I've read I think it's a scoping problem, or the way I'm calling the function, but nothing I've found makes much sense
you can't use that variable i like that while you are creating a function. If you do it so the value of i will be the last value of i. In your problem i will be length of toggler always.
so you should pass variable (i) as paramater to your onclick function,
try like this,
function makeToggle () {
for (i=0;i<toggler.length;i++) {
toggler[i].addEventListener("click", (function(d) { return function(){
toggleSection(this,d);
}; })(i), true);
}
}
or in your style,
function makeToggle () {
for (i=0;i<toggler.length;i++) {
toggler[i].onclick = (function(d) { return function(){toggleSection(this,d)}})(i);
}
}
You are seeing the problem detailed in this blog post.
The reason for this is quite complicated. The anonymous functions we define as event handlers 'inherit' the variable i from the scope of attachEventsToListItems, and not the for-loop. However, by the time the event handlers are executed, the for-loop has completed its iterations and the value of i in this function has become 4. The problem here is that the functions we define as event handlers don't create a new scope for i until they are executed.
To fix the problem, you need a closure:
for (i=0;i<toggler.length;i++) {
toggler[i].onclick= (function (index) {
return function() {
toggleSection(this,index);
};
}) (i);
}
You can see it in actor here: http://jsfiddle.net/Vb2t2/

Categories