forEach loop, stacks classes - javascript

I have a hmtl template which replicates with a forEach loop. And I use .length of the template to give the new divs class names that are unique.
The problem is that it the newest template has all the previous classes.
"residentRetainRequest check jqbr_active residentRetainRequest-0 residentRetainRequest-1 residentRetainRequest-2 residentRetainRequest-3"
How do I get rid of the previous classes and only keep the latest? So the result above is "residentRetainRequest check jqbr_active residentRetainRequest-3" instead.
Parts of the code
The reason behind:
temp.find('.residentRetainRequest').attr 'data-key', 'residentRetainRequest-' + iCnt
Is that i use another function, and use this to call it.

The problem seems to be this line of code which is always selecting all items with class residentRetainRequest:
temp.find('.residentRetainRequest').addClass("residentRetainRequest-" + iCnt);
Instead this code will select only the last item to add residentRetainRequest with current count i:
temp.find('.residentRetainRequest').last().addClass("residentRetainRequest-" + iCnt)

The solution was using .removeClass as mention.
temp.find('.residentRetainRequest').addClass("residentRetainRequest-" + iCnt)
temp.find('.residentRetainRequest').removeClass('residentRetainRequest-' + (iCnt - 1))
Therefore i will get rid of the previous classes and only have the last one remaning.

Related

jQuery for loops not running function

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

How to condense similar duplicate jquery functions

Well if my maths is right, my Jquery file is 16 times bigger than it could be.
I am building a tabbed category page which looks like this..
Tab1
cat1
cat2
etc
Tab2
cat1
cat2
etc
All content starts of hidden and then appears when a button in the category header is clicked (also toggling an arrow up/down).
$("#tabName_contentLink_cat1").click(function(){
$("#tabName_contentLink_cat1 > .arrow").toggleClass('greyArrow_down')
.toggleClass('blackArrow_up');
$("#tabName_content_cat1").slideToggle("fast");
});
This code works fine but I've repeated it 16 times!
The only part that varies is the number at the end of '_cat1'.
How can I convert this one piece of code, so that it can be reused 16 times?
I am a newbie, so please keep that in mind.
In my mind; assigning some sought of unique identifier (applicable category number), collecting it in a jQuery variable onClick and then pasted at the end of each _cat'HERE' seams like the way forward. I haven't a clue on how to carry it out though.
Thanks
you could add another class to all cat elements and then use it as selector or you can do what i did. Notice i made the code smaller, efficient. And it does what you wanted by using Function.
addClick(cat1);
addClick(cat2);
addClick(cat3);
addClick(cat4);
function addClick(x) {
$("#tabName_contentLink_"+x).click(function(){
$(this).slideToggle("fast").children(".arrow")
.toggleClass('greyArrow_down blackArrow_up');
});}
What about
$("[id^='tabName_contentLink_cat']").click(function(){
$(this).children(".arrow").toggleClass('greyArrow_down')
.toggleClass('blackArrow_up');
var contentId = this.id.replace(/contentLink/, 'content');
$("#"+ contentId).slideToggle("fast");
});
It's not the most elegant code, but it should work.
Why don't you use a simple for loop?
for(var i = 1; i <= 16; i++){
$("#tabName_contentLink_cat" + i).click(function(){
$("#tabName_contentLink_cat" + i + " > .arrow").toggleClass('greyArrow_down')
.toggleClass('blackArrow_up');
$("#tabName_content_cat" + 1).slideToggle("fast");
});
}
There are other options, but this seems to be the quickest way to make it work without changing too much of the existing code. To make it more generic you can wrap it in a function that receives 'i' as an argument.
Give them all the tabName_contentLink class, then:
$(".tabName_contentLink").click(function(){
$(this).children(".arrow").toggleClass('greyArrow_down')
.toggleClass('blackArrow_up');
$(this).find(".tabName_content").slideToggle("fast");
});
The keyword this allows you to reference the object calling the function, thus relate to a specific object out of a set. It can become a little tricky, but basically - you can use it as described above.

Easy level, selecting elements in DOM, optimization, creating method function

Please, do not laugh, too much. I know jQuery ans JS for a short a while.
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
For the first one, why do you need a selector like that? couldn't you find something less specific to hook onto? If you must keep it when joining an number and a string, JavaScript will convert the number to string behind the scenes so you don't really need the .toString() and could do the "maths" +/-1 outside of your selector making it more readable.
Edit
In regards to your comment I am not really sure what you mean, you could assign a class to the "post" items and then add the unique id to a data-attribute ID. To make it simpler you could do something like this:
var codeLt = aktywneZdanie + 1,
codeGt = aktywneZdanie - 1;
$('code:lt(' + codeLt + '):gt(' + codeGt +')').removeClass('class2');
End Edit
And the second solution should work, all your doing is passing the dom elements found from your selector into a function as a jQuery "array" in which manipulate to your needs
And for your second question why not just toggle the class on and off? having a default state which reflects class one?
jQuery('#something').toggleClass('uberClass');
Or you can pass your selector to the function
changeClasses(jQuery('#something'));
Then inside you function work on the return elements.
Edit
Your code should work fine, but id suggest checking to make sure you have got and element to work on:
changeClasses(jQuery('#something'));
function changeClasses($element){
if($element.length > 0) {
$element.addClass('class1');
}
}
End Edit
Hope it helps,
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
I stoped creating this wierd code like this one above, instead I start using .slice() (do not forget to use .index() for arguments here), .prev(), .next(). Just those three and everything is faster and clearer. Just an example of it below. No it does not do anything logical.
var activeElem = jQuery('code:first');
var old Elem;
jQuery('code').slice('0',activeElem.index()).addClass('class1');
oldElem=activeElem;
activeElem=activeElem.next();
jQuery('code').slice(oldElem.index(),activeElem.index()).addClass('class1');
oldElem.toggleClass('class1');
activeElem.prev().toggleClass('class1');
and the second part
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
This one is still unsolved by me.

Extracting values from Array with Javascript

I am having issues with getting exactly values with Javascript.
Following is working version of when we have class on single item.
http://jsfiddle.net/rtnNd/
Actually when code block has more items with same class (see this: http://jsfiddle.net/rtnNd/3), it picks up only the first item which use the class name.
My issue is that I would like to pick up only the last item which use the class name. So I used following code:
var item = $('.itemAnchor')[6];
var href = $($('.hidden_elem')[1].innerHTML.replace('<!--', '').replace('-->', '')).find(item).attr('href');
But it doesn't work though. I don't really know why.
The code that may contains items are using same class, class may be use in 2 items, 3 items, or 6th times. That's why, I want to pick up only the last item to extract.
Can you explain, thank you all for reading my question.
"My issue is that I would like to pick up only the last item which use the class name."
OK, so in a general sense you would use the .last() method:
var lastItem = $('.itemAnchor').last();
Except that there are no elements in the DOM with that class because (in your fiddles) they're all commented out. This is also the reason why the code you showed in your question didn't work. The first line:
var item = $('.itemAnchor')[6];
...sets the item variable to undefined. The selector '.itemAnchor' returns no elements, so $('.itemAnchor') is an empty jQuery object and it has no element at index 6.
You need to use the '.itemAnchor' selector on the html that you get after removing the opening and closing comments with your .replace() statements, so:
var href = $($('.hidden_elem')[0].innerHTML.replace('<!--','').replace('-->',''))
.find('.itemAnchor').last().attr('href');
Demo: http://jsfiddle.net/rtnNd/4/
EDIT in response to comment:
"How can we pick up the itemElement before that last one."
If you know you always want the second-last item use .slice(-2,-1) instead of .last(), as shown here: http://jsfiddle.net/rtnNd/5/
Or if you know you want whichever one has an href that contains a parameter h= then you can use a selector like '.itemAnchor[href*="h="]' with .find(), in which case you don't need .last() or .slice():
var href = $($('.hidden_elem')[0].innerHTML.replace('<!--','').replace('-->',''))
.find('.itemAnchor[href*="h="]').attr('href');
Demo: http://jsfiddle.net/rtnNd/6/
Note though that this last method using the attribute-contains selector is picking up elements where the href has the text "h=" anywhere, so it works for your case but would also pick up hh=something or math=easy or whatever. You could avoid this and test for just h= as follows:
var href = $($('.hidden_elem')[0].innerHTML.replace('<!--','').replace('-->',''))
.find('.itemAnchor')
.filter(function() {
return /(\?|&)h=/.test(this.href);
}).attr('href');
Demo: http://jsfiddle.net/rtnNd/7/

Using next() x number of times with jQuery

What's an easy way to iterate x number of times using next() (applying the same function each time)?
I am working in Sharepoint and have limited control of the HTML; what I can do is find an element by its ID, track down the closest <td>, hide() it, and then move on to the next one (I don't want all the <td>'s, just about 7 or 8 in a row).
The code below works but it's not that pretty.
$("#my-easily-identifiable-id").closest("td").hide();
$("#my-easily-identifiable-id").closest("td").next().hide();
$("#my-easily-identifiable-id").closest("td").next().next().hide();
$("#my-easily-identifiable-id").closest("td").next().next().next().hide();
[ ... etc ... ]
What's a better way to do this?
Thanks
PS: added a fiddle (genius)
Use .nextAll() + .andSelf() with .slice().
$("#my-easily-identifiable-id").closest("td").nextAll().andSelf().slice(0, 7);
I think a simpler solution than those posted so far would be .nextUntil():
//to get next 8 elements
var i = $('#my-easily-identifiable-id').index();
$('#my-easily-identifiable-id').closest('td').nextUntil('', ':lt(' + (i+8) + ')');
//to get self and next 3
var i = $('#my-easily-identifiable-id').index();
$('#my-easily-identifiable-id').closest('td').nextUntil('', ':lt(' + (i+3) + ')').andSelf();
Grabs all "next" elements until the filter is hit (in this case we choose the next 8 elements). Verified by jsFiddle.
I've not tried it, but perhaps the following might work (I'll test momentarily):
$("#my-easily-identifiable-id").siblings().slice($(this).index(),($(this).index() + 8)).hide();
Tested and verified with a JS Fiddle demo.
Maybe something like this:
$("#my-easily-identifiable-id").closest("td").hide();
$("#my-easily-identifiable-id").closest("td").nextAll().hide();

Categories