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.
Related
I am trying to modify a div that has a given class with the following jquery code:
$("[class^=delay-][class$='+number+']").each(function(index) {
var delayTime = $(this).attr('class').match(/delay-(\d+)/)[1];
$(this).removeClass("[class^=delay-][class$='+number+']");
$(this).data('data-wow-delay', delayTime + 's');
});
Find the divs that has delay-1, or delay-3, and so on...
Get the number as a variable.
Remove the class because I don't need it anymore.
Add to the div data-wow-delay="1s"
I am using the above script but it doesn't seem to succeed in identifying the class.
jquery wildcards don't work with removeClass
This is correct, because removeClass doesn't use a selector, it uses explicit class names - it's directly equivalent would be addClass, for which it makes no sense to have wildcards.
You can get all the classes and loop through them, giving an exact value for remove class, and, in your case for the delayTime value.
// match where all the classes might contain a relevant one
$("[class*='delay-']").each(function() {
// Keep 'this' for inside later loop
var el = $(this);
// get all the classes
var classList = el.attr('class').split(/\s+/);
// loop each class to check if it's one to remove
$.each(classList, function(index, item) {
if (item.startsWith("delay-")) {
el.removeClass(item);
var delayTime = parseInt(item.substring(6), 10);
el.data('data-wow-delay', delayTime + 's');
}
});
});
You could reduce the code with $.map, but this gives the idea.
Working fiddle: https://jsfiddle.net/hne72o8m/
The removeClass function takes a function argument since jQuery 1.4.
So it can be done with a one-liner. See Best answer in jQuery removeClass wildcard
I'm trying to make a loop in jQuery that finds all 'img' elements and places a caption below them, according to the value of the element's 'caption' attribute. Whenever I run the loop below, I am left with no captions under any of the images.
for (var i = 0; i < $('.myimage').length; i++) {
$('.myimage')[i].after('<h6>' + $('.myimage').attr('caption') + '</h6>');
};
However, when I run this code
$('.myimage').after('<h6>TEST</h6>');
the word 'TEST' appears below all of the images. Therefore I know my html is correct, I have no typos, and the selector is working, I just cannot get the for loop to work... What have I done wrong?
$('.myimage')[i] returns a DOM element (not a jQuery object) so there is no after method. If you want to loop, simply use .each
$(".myimage").each(function() {
//this refers to each image
$(this).after('<h6>' + $(this).attr('caption') + '</h6>');
});
You can loop through the .myimage elements like this, using .after()'s callback function
$('.myimage').after(function(){
return '<h6>' + $(this).attr('caption') + '</h6>';
});
One minor note, don't make up your own attributes. use the custom data attribute instead, like data-caption="something".
jsFiddle example
I am trying to run a loop over a few elements in JQuery. Before anyone says it, I do not need .each(). I am trying to run through the elements as a genuine loop- once a successful iteration runs, the loop will break and prevent the same action being done on other elements. I looked briefly at the straight JavaScript version, with the .getElement... methods, but it is my understanding that this won't satisfy my other requirement- the list of elements to be iterated over is created via a partial-string JQuery identifier:
rows = $('tr[id^="am_assetRow_' + parentAsset.replace(/ /, "_") + '_' + type + '"]');
Does anyone know of anything that might help me get this working?
EDIT: Just a bit more information on the application: I am checking to see if a value can be inserted into an existing row of a table, and if not, creating a new row and inserting it there. Thus, I need the loop to exit if a suitable fit is found, and after the loop terminates, I need to know whether it terminated in success (placing the value) or failure (no available locations- time to create a new row).
In jquery, if you want a $.each() loop to end immediately, just return false from the function call.
Do do a normal loop without using each() but still using jquery to select the items based on partial string etc...
rows = $('tr[id^="am_assetRow_' + parentAsset.replace(/ /, "_") + '_' + type + '"]');
for (var i = 0; i < rows.length; ++i) {
rows[i]; // The raw element at this index.
$(rows[i]); // jquery collection for this one element.
if (someCondition) {
break; // Break the loop early.
}
}
Here's what I have. A SharePoint 2010 custom view in a list web part. I have 6 categories and 4 sub-categories. Items do not have to have sub-category but do have to have a category.
The view shows the a blank sub-category witha number next to it. I'm trying to bind a click event to all of them but the ID increases on every page refresh. The base ID is titl[0-9]*[0-9]. Then there is another ID underneath that I want to check as well, it is titl[0-9]*_[0-9]1.
So I've tried using the regex selector for jQuery and it doesn't bind correctly. It finds the object but doesn't bind correctly.
I need it to bind to the id and then be able to trigger the onclick event of the next tbody which is the 1_. Then check if the text of it is " " and if so hide the tbody.
My code:
$(":regex(id,titl[0-9]*-[0-9]_) td a").bind('click', function(){
var parent = $(this);
var child = $(this).next("tbody");
var grandchild = $(this).next("tbody td a");
//alert(parent + " | " + child + " | " + grandchild ); //always return undefined??
// Everything below works if I can get the IDs correct for child and grandchild
if($(grandchild).css('display')!='none'){
$(grandchild).click();
if($(grandchild).text()==" "){
$(child).hide();
};
};
});
I'd strongly suggest you need to re-think your IDs - they should be consistent, really.
If you absolutely must work with a variable ID, you can use the "id" attribute in a selector as with any other attribute:
// Any element, ID starts with "titl"
$('[id^="titl"]')
To capture that and re-use it, I'd really suggest you're doing something wrong with your IDs. However, for completeness (although I can't stress enough how much you should try to avoid having to use this), something based on this should be a good (haha, yeah right) starting point
// Long-winded messy hideous foul code
var $title = $('[id^="titl"]'),
title = $title.length && $title.eq(0).attr('id');
if (title !== 0)
{
$('#' + title + ' #' + title + '1 td a').html('Ow.');
}
I'm not sure I get this, but you can target any ID starting with titl, and then filter based on the ID in many other ways inside the function:
$('[id^="titl["]').on('click', function() {
var check = this.id.charAt(10) == '_', //tenth character is underscore ?
parent = $(this),
child = $(this).next("tbody"),
grandchild = $(this).next("tbody td a");
if (check) {
//element matching second selectortype clicked
}else{
if (grandchild.is(':visible')){
grandchild.trigger('click');
if (grandchild.text()==" ") child.hide();
}
}
});
I agree about rethinking your ids if you have control over them. Even if you don't, the StartsWith selector will get you all of the higher level elements, and you can traverse to the lower level ones. Remember that chaining the selectors means that you can match on similar patterns in ids, not paying any attention to the actual values.
One other note: I've never needed to resort to a regex match with jQuery. The CSS3-like selectors are just far too powerful for that.
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);
})();