How to skip element with specific class in jQuery for loop? - javascript

I have a list of elements:
<ul id="wpsl-stores">
<li>list</li>
<li>list</li>
<li class="skipthis">list</li>
<li>list</li>
<li>list</li>
<li>list</li>
<li class="skipthis">list</li>
<li>list</li>
</ul>
I'm looping through the elements and appending the number of that element:
var locCount = $('#wpsl-stores li').length;
for (i = 1; i < locCount+1; i++) {
$('#wpsl-stores ul li:nth-child('+i+') strong:before').hide();
$('body').append('<style>#wpsl-stores ul li:nth-child('+i+') strong:before {content:"'+i+'";}</style>');
}
I need to skip the elements that have the "skipthis" class.
On the actual site, the elements with the "skipthis" class are hidden but still in the dom. This means the loop above is still counting them.
Right now, the output is something like this:
1 list
2 list
4 list
5 list
6 list
etc.
etc.
I need it to be
1 list
2 list
3 list
4 list

You should select all the elements that aren't skipthis and loop through to add:
$('#wpsl-stores li:not(.skipthis)').each(function(i,li) {
$('body').append('<style>#wpsl-stores ul li:nth-child('+(i+1)+') strong:before {content:"'+(i+1)+'";}</style>');
});
EDIT:
If you want to remove the skipthis ones and add a counter to the others:
var listCount = 0;
$('#wpsl-stores li').each(function(i,li) {
if ($(this).hasClass('skipthis')) {
$(this).remove();
} else {
listCount++;
$('body').append('<style>#wpsl-stores ul li:nth-child('+listCount+') strong:before {content:"'+listCount+'";}</style>');
}
});

How about:
for (i = 1; i < locCount+1; i++) {
var $listElt = $('#wpsl-stores ul li:nth-child('+i+') strong:before');
if (!$listElt.hasClass('skipThis') {
$listElt.hide();
$('body').append('<style>#wpsl-stores ul li:nth-child('+i+') strong:before {content:"'+i+'";}</style>');
}
}
reference

try adding .not
$('#wpsl-stores li').not( ".skipthis" )
source: http://api.jquery.com/not/

You can use .each() for iteration and .hasClass() to skip some li elements:
$("#wpsl-stores li").each(function (index, element) {
if (!$(element).hasClass('skipthis')) {
// do something
}
});

Related

JavaScript: query children and modify parent

I have a static generated unsorted list and need to modify the parent li for a given child-href-match. This action should perform by rendering, not by interaction. I am using jQuery 1.12.4.
<div id="archive_widget" class="widget-odd widget-last widget-first widget-1 widget Archive_Widget">
<h3>Archive</h3>
<ul>
<li>2018</li>
<li>2017</li>
<li>2016</li>
<li>2015</li>
<li>2014</li>
<li>2013</li>
<li>2012</li>
<li>2010</li>
<li>2009</li>
</ul>
</div>
I don't know how to do this with JS, but this imaginary JS was in my mind.
jQuery(document).ready(function() {
var current = "<?php echo $current; ?>";
var ArchiveList = document.querySelector('#archive_widget ul li').children;
for (i = 0; i < productList.length; i++) {
if (productList[i].text == current) {
$(productList[i]).parent().addClass('active-menu');
}
}
});
Thank you.
There are some problems with your code:
document.querySelector select only one element, in your case the first LI
variable productList is never declared
The parent of a LI is always a list, not the LI itself.
Here is a working version of it:
$(document).ready(function() {
var current = "2014";
var productList = $('#archive_widget ul li a'); // select all A elements
for (i = 0; i < productList.length; i++) {
if ($(productList[i]).text() === current) {
$(productList[i]).parent().addClass('active-menu'); // Parent of A will be LI
}
}
});
Ideally, this would be set when SSR, but here's a scant attempt:
$(document).ready(function () {
let current = "2015";//set server-side
let found = false;
$("#archive_widget").children('ul').children("li").children("a").each(function () {
if (!found && $(this).text() === current) {
$(this).parent().addClass('active-menu');
found = true;
}
});
});
.active-menu { background: red }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="archive_widget" class="widget-odd widget-last widget-first widget-1 widget Archive_Widget">
<h3>Archive</h3>
<ul>
<li>2018</li>
<li>2017</li>
<li>2016</li>
<li>2015</li>
<li>2014</li>
<li>2013</li>
<li>2012</li>
<li>2010</li>
<li>2009</li>
</ul>
</div>
I hope this helps!
Change ArchiveList to productList since that's what your code is using and use .textContent instead of .text.
Your query selector only matches one element. You want to match all of the anchor elements whose parents are a li, so use document.querySelectorAll instead:
document.querySelectorAll('#archive_widget ul li a');
Fixed Code:
jQuery(document).ready(function() {
var current = "<?php echo $current; ?>";
var productList = document.querySelectorAll('#archive_widget ul li a');
for (i = 0; i < productList.length; i++) {
if (productList[i].textContent == current) {
$(productList[i]).parent().addClass('active-menu');
}
}
});

Is there any programmtical way where I can remove class of list item

I am doing one loop where I am matching with some value and assigning class="hidden" to list. But When I run again the loop I want all my list should be without class, so I can assign for other value.
Here is my code.
for (i = list.children.length; i--;) {
li = list.children[i];
match = li.textContent.toLowerCase().indexOf(value.toLowerCase()) > -1;
li.classList.toggle('hidden', !match)
}
But before I run this loop I want all the list without any class so hete in the list I want to remove Class="hidden"
<li class="hidden">
Albania
</li>
Can anyone help me to achieve this
You want to do this before your existing loop? Try this:
var list = document.getElementById("list");
for (i = list.children.length; i--;) {
li = list.children[i];
li.classList.remove("hidden");
}
<ul id="list">
<li class="hidden">foo</li>
<li>bar</li>
<li class="hidden">baz</li>
</ul>
Though it does look like you could do this in the beginning of your existing loop. No need for another loop before that one.
Why not use a combo of Element.classList.contains(), ..remove(), ..add() etc. Lots of info on the MDN page.
For example:
for(i=list.children.length; i--;) {
li = list.children[i];
if (li.textContent.toLowerCase().indexOf(value.toLowerCase()) > -1) {
li.classList.add('hidden');
// or is it li.classList.remove('hidden'); here?
}
}
It is safe to ..add() even if the element has the class already. The class will not be added twice.

Populating ul list with index

I am having trouble populating a ul li with its index value.
My HTML below.
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
My JS below.
$('document').ready(function(){
var indexus = $('li').index();
$('li').each(function(){
$('li').html(indexus);
});
});
JS Fiddle: http://jsfiddle.net/kuJWc/407/
I want to populate the li with its appropriate li index value, but I can only end up getting the index value of the latest (in this case 3). How would I go about looping in each index value so that each li shows the value of its own index number?
you should do like this:
$('li').each(function(){
$(this).html($(this).index());
});
you were adding the index to all the li.. so istead of $(this) inside of the each, you were using $('li'). which adds the last value li index to all of them.
Try this:
$('document').ready(function(){
$('li').each(function(){ // iterate through each `li`
var $li = $(this); // get the current `li` element
var index = $li.index(); // get the current `li` index
$li.html(index); // set the `li`'s html to the index value
});
});
I added some comments to help you understand what each step does, I hope that helps!
What about this:
$('document').ready(function(){
var indexus = $('li');
for (var i = 0; i <= indexus.length; i++) {
$(indexus[i]).html(i);
}
});
Here it works.
You can get an array of the ul's children and then iterate over each of the children with something like this:
var arr = $('ul').children();
for (var i = 0; i < arr.length; i++){
$(arr[i]).html(i);
}

Wrap navigation in a subnavigation

I have a dynamically created navigation, where i can not make parent/child list for navigation.
I want to add a link named "More..." at the end of the list, according to available space. And then show all remaining elements as child of More...
For example if i have elements list1, list2, list3, ..... list10.
It will be displayed as list1, list2, list3, more... and rest of the links will be child of more...
I tried creating a script for this, and i think i am very close. But i have following 2 issues:
How to add UL around child list.
Sometimes "More..." is broken to next line.
Following is my JS code:
$(document).ready(function() {
var nav = $('ul');
var more = '<li>More...</li>';
nav.prepend( more );
var availableSpace = nav.innerWidth();
var list = 0;
var countedSpace = 0;
$('li').each(function(){
var current = $(this);
countedSpace = countedSpace+current.outerWidth();
if (countedSpace < availableSpace) {
list++;
}
})
var showInList = list; //Space available for xx no. of items.
var newList = [];
// Start at 2, don't include dynamically added more link.
for (i = 2; i < showInList; i++) {
newList.push($(nav).find("li:nth-child("+i+")"));
}
newList.push(more);
var childList = [];
for (i = showInList; i <= nav.children().length; i++) {
childList.push($(nav).find("li:nth-child("+i+")"));
}
//nav.empty();
nav.html(newList);
$(nav).find("li:last-child").append(childList);
});
jsfiddle: http://jsfiddle.net/alokjain_lucky/Lhh019ru/
1. How to add UL around child list.
Try creating a jquery UL object and then appending the li items to it. Like this:
var ulChildren = $("<ul/>").append(childList);
$(nav).find("li:last-child").append(ulChildren);
2. Sometimes "More..." is broken to next line.
This is happening because the li children are visible and stacking to the right, try adding
li ul{
display:none;
}
to test the correct layout, after step 1.
Here is an example of the above on JSFiddle, click on "More..." to toggle children visibility
Example code
I think this will accomplish what you're looking for:
var availableWidth= $('ul').innerWidth();
var totalWidth= $('<li class="more">More</li>').appendTo($('ul')).outerWidth();
$('li').each(function(index) {
totalWidth+= $(this).outerWidth();
if(totalWidth >= availableWidth) {
$('ul li:eq('+(index-2)+')').after(
$('.more').click(function() {
$('ul li:gt('+(index-1)+')').toggle()
})
);
$('ul li:gt('+(index-1)+')').css({
display: 'none'
});
return false;
}
});
var availableWidth= $('ul').innerWidth();
var totalWidth= $('<li class="more">More</li>').appendTo($('ul')).outerWidth();
$('li').each(function(index) {
totalWidth+= $(this).outerWidth();
if(totalWidth >= availableWidth) {
$('ul li:eq('+(index-2)+')').after(
$('.more').click(function() {
$('ul li:gt('+(index-1)+')').toggle()
})
);
$('ul li:gt('+(index-1)+')').css({
display: 'none'
});
return false;
}
});
ul {
padding:0px;
margin:0px;
border:1px solid #ccc;
overflow:hidden;
width: 500px;
}
li {
list-style:none;
float:left;
margin:10px;
border:1px solid #f1f1f1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>a Home</li>
<li>b Services</li>
<li>c Meet our team</li>
<li>d work process</li>
<li>e About us</li>
<li>f Contact us</li>
<li>g Meet out team</li>
<li>h work process</li>
<li>i About us</li>
<li>j Contact us</li>
</ul>
totalWidth is initialized as the width of the More list item. I gave it a class of more, so it could be referred to within each.
When totalWidth is greater-or-equal-to availableWidth, .more is inserted in the appropriate position (index) of the ul.
The click handler toggles the display of list items at higher positions. Those higher-positioned list items are then hidden.
return false prevents each from continuing to run once this is done.

Pure javascript way to update CSS class attribute from all list items?

I'd like to use Javascript (not jquery) to access all items in a <ul> list and remove the active class from everything except my chosen menu item.
Here is the list:
<ul id='flash-menu'>
<li id="menu1" class='something active'>item 1</li>
<li id="menu2" class='somethingelse'>item 2</li>
<li id="menu3" class='somethingelse'>item 3</li>
</ul>
This is my javascript:
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0 ; i<list_items.length ; i++){
list_items[i].className = list_items[i].className.replace('/\bactive\b/','');
}
document.getElementById(view_name).className += " active";
}
The last line of the Javascript (adding the active class) works, but I don't think I'm accessing the list items right to remove the classes from the other items. Any suggestions? - thanks!
First off, your regex is wrong:
list_items[i].className.replace(/\bactive\b/, '');
Note: No quotes on regex'es in JavaScript. A slighty altered, working version is available on JsFiddle.
Furthermore, I get a few instances of HTMLTextElements in list_items. They're breaking the loop (Fx3.6/Win7) when trying to access the non-existing className attribute. You can avoid this by either using:
var list_items = document.getElementById('flash-menu').getElementsByTagName('li');
// Selecting _all_ descendant <li> elements
or by checking for the existence of .className before read/write within the loop body (example). The latter is probably the cleanest choice since it still only affects direct children (you may have several levels of <ul>s in each <li>).
I.e.,
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0, j=list_items.length; i<j; i++){
var elm = list_items[i];
if (elm.className) {
elm.className = elm.className.replace(/\bactive\b/, '');
}
}
document.getElementById(view_name).className += ' active';
}
You can use javascript function getElementsByTagName:
var listitems = document.getElementsByTagName("li");
this would return an array of all the lists and can be iterated for each list element and processed as required.
You can try:
In the case that you can have more than ul, first you have to get all references to them and then process each ul:
var uls = document.getElementsByTagName("ul");
for (uli=0;uli<uls.length;uli++) {
ul = uls[uli];
if (ul.nodeName == "UL" && ul.className == "classname") {
processUL(ul);
}
}
An illustration of proccessUL can be:
function processUL(ul) {
if (!ul.childNodes || ul.childNodes.length == 0) return;
// Iterate LIs
for (var itemi=0;itemi<ul.childNodes.length;itemi++) {
var item = ul.childNodes[itemi];
if (item.nodeName == "LI") {
// Iterate things in this LI
in the case that you need it put your code here
.....
}
}
}
Of course you can also use: item.className = "classname"; if you dont need to iterate between childs of LI
document.getElementById('flash-menu').childNodes will also include white space nodes.
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').getElementsByTagName('li'), i;
for (i=0 ; i<list_items.length ; i++){
if (list_items[i].className.indexOf('active') > -1) {
list_items[i].className = list_items[i].className.replace(/\bactive\b/,'');
}
}
document.getElementById(view_name).className += " active";
}
i agree with jensgram,and you'd better code like this:
list_items[i].className.replace(/\bactive\b/g, '');
add the regex string a 'g'
g is for Global ,using ‘/g’ can replace all the same Which Match the regex ,but if you don't use '/g',you just replace the first string .
like this :
var test= "testeetest" ;
alert(test.replace(/e/,"")) ;//result
: tsteetest but using 'g' var
test= "testeetest" ;
alert(test.replace(/e/g,"")) ;//result
: tsttst
Have a look at this here: https://developer.mozilla.org/en-US/docs/Web/API/element.classList
It helped me a lot with finding class elements!
This is my solution, maybe not the best, but for my works fine.
window.addEventListener('load', iniciaEventos, false);
function iniciaEventos(e)
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++ )
{
menu[i].addEventListener('mousedown', clickMenu);
}
}
function clickMenu()
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++)
menu[i].classList.remove('active');
this.classList.add('active');
}

Categories

Resources