Using jQuery, how would you show() every div.foo on a page in a random order, with a new one appearing every X milliseconds?
Clarification: I want to start with all these elements hidden and end with all of them showing, so it wouldn't make sense to show() the same element twice.
I originally thought I'd make an array listing all the elements, randomly pick one, show that one, remove it from the array using splice(), and then randomly pick the next one from the remaining list - etc. But since my array is part of a jQuery object, splice() is not available.
An interesting way to do this would be the extend Javascript's Array base object with a shuffle function. In Prototype (should be the same in JQuery, except jQuery.extend). This is quick and dirty shuffle, there are plenty of other ways to do it.
Object.extend(Array.prototype, {
shuffle : function() {
this.sort( function() { return 0.5 - Math.random(); } );
return this;
}
});
So assuming you have your array of divs ready to go, call the shuffle() method and simply go through them one by one, in order (they're now shuffled) and show them (according to your intervals). Might want to make that 'non-destructive' though by cloning the array returned by the shuffle method instead of sorting it directly.
I don't use jQuery myself, but what about this:
var intervalMilliseconds = X; // set to your value for X
var divFoos = $("div.foo").get();
var intervalId = setInterval(function() {
$(divFoos.splice(Math.floor(Math.random() * divFoos.length), 1)).show();
if(divFoos.length == 0) clearInterval(intervalId);
}, intervalMilliseconds);
That should do the trick.
UPDATE: Since your description isn't explicit about it, I assumed you meant that you ultimately want to show all of them, and that once they are visible, we are done. If not, please explain further so I can update this (if you can't already determine what you need from the code I provided).
Here's how I would do it (untested):
(function () {
var int, els;
int = 100; // interval, in milliseconds
els = $('div.foo');
setInterval(function () {
var idx;
idx = Math.floor(els.length * Math.random());
$(els[idx]).show();
setTimeout(function () {
$(els[idx]).hide();
}, int);
}, int);
})();
Related
I have 8 elements in sequence that each represent a yoga pose. When one of these elements is clicked I want to add/remove classes for all the pose cards that come before and after the clicked element. So far I have been able to get the index of the clicked element using the following:
$(".pose-card").click(function () {
clickedPoseIndex = $(".pose-card").index(this);
});
And then I tried to use a filter function to get the ones whose index is less than the clicked one with something like this:
let prevPoses = $(".pose-card").filter(function () {
return parseInt($(".pose-card").index(this) < clickedPoseIndex);
});
But that did not work! Please let me know if you can think of any better solutions. Much appreciated!
What you want to do inside filter is get the index as int (hence the parseInt function) and compare with the value you've stored in clickedPoseIndex which is already an int. You've simply missed a bracket or misplaced one. All you have to do is:
let prevPoses = $(".pose-card").filter(function () {
return parseInt($(".pose-card").index(this)) < clickedPoseIndex;
});
Edit
Don't need to use parseInt either as the value returned is already an int so:
return $(".pose-card").index(this) < clickedPoseIndex;
As far as I know we can clearInterval as:
var go = setInterval(function() {
console.log("go");
}, 5000);
clearInterval(go);
But for some reason in my javascript code I have same variable being assigned two time the setInterval. Now even if I clear it multiple times it doesn't get cleared. Example:
var go = setInterval(function(){
console.log("go");
}, 1000);
var go = setInterval(function(){
console.log("go");
}, 1000);
clearInterval(go);
clearInterval(go);
clearInterval(go);
clearInterval(go);
My questions is:
What is going on here? How does javascript deal with this situation? What's wrong with go? Why doesn't it get cleared?
You cannot. You've overwritten the previous timer id. It's lost.
Only the second interval, with the id that is currently stored in the variable, will get cleared, regardless how often you call clearInterval.
You will need multiple variables (or a datastructure of timers, e.g. an array):
var go1 = setInterval(function(){
console.log("go 1");
}, 1000);
var go2 = setInterval(function(){
console.log("go 2");
}, 1000);
clearInterval(go1);
clearInterval(go1); // nothing will happen
clearInterval(go2);
As mentioned in some of the comments, what you've done here is reassign your go variable. Each call to setInterval returns a different id. Once you've reassigned the only variable referencing that value, the previous value is lost.
When it comes to unique identifiers, it's batter to keep an expandable list of them so that you won't lose the identifier for the process. I suggest making an array and pushing each new id to it (using it much like a stack), that way they are all in one place but are still able to be individually referenced:
var intervalIDs = []; //we would want something like this to be a global variable
//adding IDs to the array:
intervalIDs.push(window.setInterval(function(){console.log("go 1");}, 1000));
intervalIDs.push(window.setInterval(function(){console.log("go 2");}, 1000));
//now we know we can find both IDs in the future
//clearing an interval:
window.clearInterval(intervalIDs.pop()); //takes the last ID out of the array and uses it to stop that interval. this could be done in a for loop to clear every one you've set using the above method.
//OR if you happen to know the index (in the array) of a specific interval id you want to clear:
var index = /*index number*/;
window.clearInterval(intervalIDs.splice(index, 1)[0]);
The point is to ensure that you maintain the means of referencing your intervals (or anything else that acts similarly, for that matter).
I am displaying rotating images.
var pics= [
"images/img1.jpg",
"images/img2.jpg",
"images/img3.jpg",
];
And would want it to stop onClick.
function StopRotate(interval, imgIndex) {
clearInterval(interval);
var permanentImage = picture[imgIndex].src;
picture[imgIndex].src = permanentImage;
pics.splice(pics.indexOf(picture[imgIndex].src), 1);
}
Here's how I rotate the images (this block has three occurrences for three image containers):
interval0 = setInterval(function () {
if(pics.length != 1) {
picture[0].src = pics[count];
count++;
if (count == pics.length) count = 0;
}
else picture[0].src = pics[0];
}, 10);
But the image occurs yet again to other frames even if the path has been already removed from the array. I tried this using 12 images. Some times when I run it, the src turns out to be undefined.
Also if I click the images unordered, the images from other frames becomes blank. In this sample, I have three images, if I clicked on the third container, the first container becomes blank, how does that affect other frames when the interval functions are separate. There's no problem however when clicking it in order. Note I have changed the sequence where I put the if condition inside setInterval.
The .src property will return a fully qualified pathname which will never be found in your array of partial path names when you try to look for it with .indexOf().
You can use .getAttribute("src") to get what is actually in the HTML and that should then match what you have in your array.
Example: http://jsfiddle.net/jfriend00/3H8XF/
I would like to animate to clear out a list of items at slightly different times, say in 20ms intervals. (Think of Android 4.2 alert screen when you clear messages).
However, I can't figure out how to addClass to different elements in an array at interval time. I've tried this, but this just applies the jQuery to the last element:
for item in App.itemsController.content
jQuery('#box').delay(2000).queue (n) ->
selector = '.' + item.objectId
console.log selector
$(selector).addClass('animated fadeOutRightBig')
I've also tried setTimeout() and setInterval() to no avail.
Thanks.
You need to use a closure to keep a reference to the item variable. I don't use CoffeeScript but in javascript I would do this.
var box = jQuery('#box');
for (var i in App.itemsController.content) {
var item = App.itemsController.content[i];
(function(item) {
box.delay(2000).queue(function() {
var selector = '.' + item.objectId;
$(selector).addClass('animated fadeOutRightBig');
});
}(item));
}
Maybe this is how you do it in CoffeeScript? Just had a quick look at the syntax.
for item in App.itemsController.content
do (item) ->
jQuery('#box').delay(2000).queue (n) ->
selector = '.' + item.objectId
console.log selector
$(selector).addClass('animated fadeOutRightBig')
You should also make a reference to the #box element outside the loop, otherwise your program has to search the DOM on every iteration.
First, I apologize. I know what I want to do, but not what I should call it or quite how to ask it, so my googling was unfruitful.
I have some animation I'm using to show/hide text. I'm trying to wrap it up all nice in an object, but the way I'm doing it, I have to run some calculation code each time, as I don't know which section it is being stored with.
Now, what I hate is that I'm re-running a calculatePositions(entry); function on every pass rather than using a saved value. Trouble is, this will happen on multiple elements so the positions array needs to change. Is there a way save the positions array to a specific DOM element and just calculate it once? Can I attach these functions and properties to DOM elements rather than pass in the entry object every time?
My code:
var theShort = {};
theShort.toggle = function(){
var positions = new Array;
function calculatePositions(entry){
/*
positions = Nasty calculation code
*/
}
function showLong(entry){
calculatePositions(entry);
//My toggle code is obviously more complex and uses the positions array.
//But for simplicity sake, I've omitted it
$(entry).find('.tsl-theshort').show();
$(entry).find('.tsl-thelong').hide();
}
function showShort(entry){
calculatePositions(entry);
$(entry).find('.tsl-theshort').show();
$(entry).find('.tsl-thelong').hide();
}
return {
init: function (){
$('.tsl-showLong').click(function(){
showLong($(this).closest('.entry-content'));
return false;
});
$('.tsl-showShort').click(function(){
showShort($(this).closest('.entry-content'));
return false;
});
}
};
}();
jQuery(document).ready(function($){
theShort.toggle.init();
});
If you're worried about running the calculation function every time, set up a cache based on the element's id. If each element has a unique ID in the dom, you could do something like
var cache = {};
function showLong(entry){
var id = $(entry).attr('id');
if(!cache[id])
cache[id] = calculatePositions(entry);
//My toggle code is obviously more complex and uses the positions array.
//But for simplicity sake, I've omitted it
$(entry).find('.tsl-theshort').show();
$(entry).find('.tsl-thelong').hide();
}
function showShort(entry){
var id = $(entry).attr('id');
if(!cache[id])
cache[id] = calculatePositions(entry);
$(entry).find('.tsl-theshort').show();
$(entry).find('.tsl-thelong').hide();
}
Then, when you wish to lookup the calculation of an element,
var id = $(element).attr('id');
var calculation = cache[id];