This question is related to this one Clear all setIntervals
I'm using setIntervals within each function like so,
var allIntervals = [];
$(".elements").each(function() {
var myInterval = setInterval(function() {
// code that changes $(this)
});
allIntervals.push(myInterval);
});
I then clear all the intervals like this
jQuery.each(allIntervals, function(index) {
window.clearInterval(allIntervals[index]);
});
I now realized that I want to instead clear intervals of elements that are no longer in the DOM.
So how do I link the setIntervals to each() element, then check if the element is still in the DOM, and if not, clear the Interval associated with that element?
You can store the element with the ID from the timeout in an object, but you have to check again to see if it's in the DOM as the stored element doesn't magically dissapear from the variable, it's just no longer in the DOM.
var allIntervals = [];
$(".elements").each(function(i, el) {
var myInterval = setInterval(function() {
// stuff
}, 1000);
allIntervals.push({id : myInterval, elem : this});
});
$.each(allIntervals, function(index, item) {
if ( $(document).find(item.elem).length === 0 ) window.clearInterval(item.id);
});
FIDDLE
Use an object to store the information (with the element and the intervalid as properties), loop through the object and clear the interval if the DOM element if not available.
$(function() {
var intervals = [];
$(".elements").each(function() {
var myInterval = setInterval(function() {
// code that changes $(this)
});
var obj = new Object();
obj.element = $(this);
obj.intervalId = myInterval;
intervals.push(obj);
});
$.each(intervals, function(index, val) {
console.log(val.element);
if (val.element.length > 0) {
window.clearInterval(val.intervalId);
}
});
});
Related
I'm trying to do something very simple, but I'm obviously doing something wrong. Here is the code:
var targets = Array(
$('.someDiv'),
$('.myDiv')
);
// This "for" loop check if the Class exists and if so it runs a code
for (var i = targets.length - 1; i >= 0; i--) {
// make the target a jQuery object
var $target = targets[i];
// if the target exists
if ( $target.length > 0 )
{
console.log($target);
// run some code after every image is loaded
$target.imagesLoaded( function()
{
console.log($target);
$target.addClass('blue');
});
}
}
which somehow doesn't work.
The JsFiddle example is here
Is it just impossible to pass a variable without hacking imagesLoaded plugin? Or am I missing something?
Good news: Your code works!
var myVar;
$('.myDiv').imagesLoaded( function() {
console.log(myVar);
});
myVar is undefined as you did not define it.
... try var myVar = "Hello World";
If you want the variable to retain the value it had when calling imagesLoaded(), you can use an IIFE:
var myVar = 'someContent';
(function(myVar) {
$('.myDiv').imagesLoaded( function() {
console.log(myVar);
});
})(myVar);
Take this example:
var myVar = 'some content';
(function(myVar) {
setTimeout(function() {
console.log(myVar);
}, 1000);
})(myVar);
myVar = 'some other content';
console.log(myVar);
It will log some other content and then, a bit later some content, as was the initial value.
The problem is that the imagesLoaded callback is fired after you have already iterated over the elements. Which means that by the time the first callback is fired, $target is a reference to the last element in the array.
Fortunately, since you are just trying to get a reference to the element that imagesLoaded was called on, you can get a reference to it with this.
Updated Example
var targets = [$('.someDiv'), $('.myDiv')];
for (var i = 0; i < targets.length; i++) {
var $target = targets[i];
if ($target.length) {
$target.imagesLoaded(function () {
$(this).addClass('blue');
});
}
}
Alternatively, you could also use the $.each() function in order to store the context on each iteration:
Updated Example
var targets = [$('.someDiv'), $('.myDiv')];
$.each(targets, function (i) {
var $target = targets[i];
if ($target.length > 0) {
$target.imagesLoaded(function () {
$target.addClass('blue');
});
}
});
I have an array called RotatorNames. It contains random things but let's just say that it contains ["rotatorA","rotatorB","rotatorC"].
I want to loop through the array, and for each item i want to trigger a click event. I have got some of this working, except that the everything get's triggered instantly. How can i force the loop to wait a few seconds before it continues looping.
Here's what i have.
function Rotator() {
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
RotatorNames.forEach(function(entry){
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000);
});
}
You can run this to see what my issue is. http://jsfiddle.net/BxDtp/
Also, sometimes the alerts do A,C,B instead of A,B,C.
While I'm sure the other answers work, I would prefer using this setup:
function rotator(arr) {
var iterator = function (index) {
if (index >= arr.length) {
index = 0;
}
console.log(arr[index]);
setTimeout(function () {
iterator(++index);
}, 1500);
};
iterator(0);
};
rotator(["rotatorA", "rotatorB", "rotatorC"]);
DEMO: http://jsfiddle.net/BxDtp/4/
It just seems more logical to me than trying to get the iterations to line up correctly by passing the "correct" value to setTimeout.
This allows for the array to be continually iterated over, in order. If you want it to stop after going through it once, change index = 0; to return;.
You can increase the timeout based on the current index:
RotatorNames.forEach(function(entry, i) {
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000 + (i * 1000)); // wait for 5 seconds + 1 more per element
});
Try:
var idx = 0;
function Rotator() {
var RotatorNames = ["rotatorA", "rotatorB", "rotatorC"];
setTimeout(function () {
console.log(RotatorNames[idx]);
idx = (idx<RotatorNames.length-1) ? idx+1:idx=0;
Rotator();
}, 5000);
}
Rotator();
jsFiddle example
(note that I used console.log instead of alert)
Something like this should do what you're after:
function Rotator(index){
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
index = (index === undefined ? 0 : index);
var $btn = $("#btn_"+RotatorNames[index]);
$btn.click();
if(RotatorNames[index+1]!==undefined){
window.setTimeout(function(){
Rotator(index+1);
}, 500);
}
}
I have something like this:
var stopwatch = function (item) {
window.setInterval(function () {
item.innerHtml = myInteger++;
}, 1000);
}
This code was supposed to display myInteger, but it is not updating values of item. Why (item is a div with text inside)?
There could be a lot of reasons (we need to see more of your code), but here is a working example:
var myInteger = 1,
stopwatch = function (item) {
window.setInterval(function () {
item.innerHTML = myInteger++;
}, 1000);
}
stopwatch(document.querySelector('div'));
Important changes:
Calling stopwatch (you probably do this)
- innerHtml +innerHTML (the case matters). You won't get an error for setting innerHtml; it will set that property and you won't notice anything.
Initialize myInteger.
http://jsfiddle.net/Q4krM/
Try this code :
var stopwatch = setInterval(function (item) {
item.innerHtml = myInteger++;
}, 1000);
This should work
I want to loop over an array continuously on click. Extra props if you can work in a delay between class switches :-)
I got this far:
// Define word
var text = "textthing";
// Define canvas
var canvas = 'section';
// Split word into parts
text.split();
// Loop over text
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class').addClass(val);
});
});
Which is not too far at all :-)
Any tips?
The following will wait until you click the selected element(s) in the var el. In this example var el = $('section') will select all <section>...</section> elements in your document.
Then it will start cycling through the values in cssClassNames, using each, in turn as the css class name on the selected element(s). A delay of delayInMillis will be used between each class change.
var cssClassNames = ['c1', 'c2', 'c3'];
var el = $('section');
var delayInMillis = 1000;
// Loop over text
el.click(function() {
var i = 0;
function f() {
if( i >= cssClassNames.length ) {
i = 0;
}
var currentClass = cssClassNames[i];
i += 1;
el.removeClass().addClass(currentClass);
setTimeout(f, delayInMillis);
}
f();
});
I believe you want a delay of X milliseconds between removing a class and adding a class. I'm not sure that you have to have the lines marked // ? or even that they do the job, but what you do have to have is a way to get the value's into the function. Also, the setTimeout anon function might not actually need the parameters, but it should give you an idea.
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class')
var $canvas = $(canvas) //?
var class_val = val //?
setTimeout(function ($canvas, class_val) {
$canvas.addClass(class_val);
}, 2000);
});
});
Edit: I'd do this instead
function modify_element($element, class_name){
$element.removeClass('class');
setTimeout(function ($element) {
$element.addClass(class_name);
}, 1000);
//adds the class 1 second after removing it
}
$(canvas).click(function() {
$.each(text, function(key, val) {
setTimeout(modify_element($(canvas), val),2000);
//this will loop over the elements with 2 seconds between elements
});
});
"loop over an array continuously" this sounds like a infinite loop, I don't think you want that. About pausing the loop, this is possible, you can use this
I am essentially adding radio-buttons functionality to buttons with the class "tagbutton". There is a flaw with my code, because _this is never _last...
taguid = "";
_last = "";
$('.tagbutton').live('click', function() {
_this = $(this);
if(_last) {
//There was a last object
if(_last == _this) { // The last object was the current object
alert('deactiveate for this obj');
} else { // The last object was not the current object
alert('deactivate last, activate this');
}
} else {
alert('first object activated');
var taguid = $(this).prev().attr('data-uid');
alert(taguid);
_last = $(this);
}
});
It's because the objects' references aren't the same. A simpler way might be to activate the clicked one, then deactivate the last one. It'll have the same effect:
var taguid = "";
var _last;
$('.tagbutton').live('click', function() {
if(_last) {
// There was a last object
// Activate this
// Deactivate last
} else {
alert('first object activated');
var taguid = $(this).prev().attr('data-uid');
alert(taguid);
_last = $(this);
}
});
The jQuery function $() returns a jQuery object, and when you call it a second time you get back a different object.
However, within your event handler the keyword this refers to the actual DOM element, so if you save that directly then your comparison should work:
_this = this;
// and then later
_last = this;