Get Element with most children of specific class - javascript

I have a navigation that looks like this:
<div class="sub_navigation">
<ul>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level</li>
</ul>
</li>
</ul>
</li>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level
<ul>
<li>Fourth Level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Basically, everly li can have an infinite amount of children uls. I need to get the number of the highest level
For example, right now I'd be looking for the number 4 as the second li has 4 Levels.
I tried two different methods:
First, my own attempt that failed miserably:
$count = 1;
$('.sub_navigation > .menu > li').each(function() {
countChildren($count);
});
function countChildren() {
$(this).children('ul').each(function() {
$count++;
console.log($count);
});
return($count);
}
Second, a way I took from stack overflow but that didn't work out for me either, only returning 0 everytime:
var arr = []; //populate the length of children into this array.
$('.sub_navigation ul').map(function (i) {
arr[i] = $(this).children('ul').length;
});
var maxValue = Math.max.apply(Math, arr); //get the max value from the array
console.log(maxValue);
Could someone please point me in the right direction? I sadly have no idea how to acieve this at all anymore.
Thanks a lot!

You can use parentsUntil() like
var temp = $('.sub_navigation li').map(function() {
return $(this).parentsUntil('.sub_navigation', 'ul').length;
}).get();
var max = Math.max.apply(Math, temp);
snippet.log('Count: ' + max)
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sub_navigation">
<ul>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level</li>
</ul>
</li>
</ul>
</li>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level
<ul>
<li>Fourth Level
<ul>
<li>Fifth Level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

Instead of going from top to bottom level you could do it the other way.
Check for each li how many ul ancestors it has
var ulAncestorsPerLi = $( '.sub_navigation li' ).map(function(){
return $(this).parentsUntil( '.sub_navigation', 'ul' ).length;
}).get(),
deepestLevel = Math.max.apply( Math, ulAncestorsPerLi );
alert( deepestLevel );
var ulAncestorsPerLi = $('.sub_navigation li').map(function() {
return $(this).parentsUntil('.sub_navigation', 'ul').length;
}).get(),
deepestLevel = Math.max.apply(Math, ulAncestorsPerLi);
alert(deepestLevel);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sub_navigation">
<ul>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level</li>
</ul>
</li>
</ul>
</li>
<li>First Level
<ul>
<li>Second Level</li>
<li>Second Level
<ul>
<li>Third Level
<ul>
<li>Fourth Level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

Related

How to randomly order two synchronized lists using javascript?

Aparently shuffling an array is not so complicated:
How to randomize (shuffle) a JavaScript array?
But what if I have to (Html DOM) lists that are synchronized and I need to shuffle the order of the elements, but they should have the same final order?
For example, initial state:
<!-- List A) -->
<ul>
<li>First title</li>
<li>Second Title</li>
<li>Thrid title</li>
</ul>
<!-- List B) -->
<ul>
<li>First text</li>
<li>Second text</li>
<li>Thhird text</li>
</ul>
After shuffle:
<!-- List A) -->
<ul>
<li>Second title</li>
<li>First Title</li>
<li>Thrid text</li>
</ul>
<!-- List B) -->
<ul>
<li>Second text</li>
<li>First text</li>
<li>Third text</li>
</ul>
How can this be achieved?
Get length of items and loop through it and in loop generate random number and using generated number select an li and append it end of parent.
var ul = document.querySelectorAll("ul");
var length = ul[0].querySelectorAll("li").length;
for (var i=0; i<length; i++){
var rand = Math.floor(Math.random()*(length));
ul.forEach(function(ele){
ele.appendChild(ele.querySelectorAll("li")[rand]);
});
}
<ul>
<li>First title</li>
<li>Second Title</li>
<li>Thrid title</li>
</ul>
<ul>
<li>First text</li>
<li>Second text</li>
<li>Thhird text</li>
</ul>
Also you can use jQuery to write less code
var $ul = $("ul:first li");
$ul.each(function(){
var rand = Math.floor(Math.random()*$ul.length);
$("ul").each(function(i, ele){
$("li", ele).eq(rand).appendTo(ele);
});
});
$("button").click(function(){
var $ul = $("ul:first li");
$ul.each(function(){
var rand = Math.floor(Math.random()*$ul.length);
$("ul").each(function(i, ele){
$("li", ele).eq(rand).appendTo(ele);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>
<ul>
<li>First title</li>
<li>Second Title</li>
<li>Thrid title</li>
</ul>
<ul>
<li>First text</li>
<li>Second text</li>
<li>Thhird text</li>
</ul>
You can easily shuffle an DOM html in various number of ways. One way that is easy to understand is to convert the DOM elements into an array, then randomly splice each element out of its parent array and append them back to the parent DOM element.
In my snippet below, I used jQuery to make the code easier to read, but it can be done with native javascript just as well.
$('#shuffle').click(function(){
var items = []; // start with an empty array
$('#list_a li').each(function(i,d){
items.push(d); // add all li items into the array in their current order
});
$('#list_a').html(''); // clear the ul list
// execute this loop as many times as items.length
for(var i=items.length-1; i>=0; i--) {
var r = Math.floor(Math.random()*items.length); // pick a random array position
var item = items.splice(r,1); // take that item out of the array
$('#list_a').append(item); // append it back to the ul
}
});
ul
{
background-color: #def;
display: inline-block;
border: 1px solid grey;
padding: 30px;
border-radius: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<b>List A</b>
<ul id="list_a">
<li>First Item</li>
<li>Second Item</li>
<li>Third Item</li>
<li>Fourth Item</li>
<li>Fifth Item</li>
</ul>
<button id="shuffle">Shuffle</button>

jQuery - Expand Tree View up to selected node level

I am trying to expand the tree view up to selected node level. But I am not getting any idea about this please can any one help me on this.
For example We clicked on 'Parent d' in 'Category list' then expand 'Tree View List' up to 'Parent d' level for more details check Here
HTML
<h3>
Category list
</h3>
When click on any li expand tree list up to selected level
<ul id='category'>
<li li-id='1' id='1'>Parent 1</li>
<li li-id='2' id='2'>Parent 2</li>
<li li-id='3' id='3'>Parent 3</li>
<li li-id='4' id='4'>Parent 4</li>
<li li-id='5' id='5'>Parent c</li>
<li li-id='6' id='6'>Parent d</li>
<li li-id='7' id='7'>Parent a</li>
<li li-id='8' id='8'>Parent b</li>
<li li-id='9' id='9'>Parent e</li>
<li parent-id='5' li-id='10'>Parent x</li>
</ul>
Tree View List
<h3>
Node View
</h3>
<div class='tree'>
<ul id='ulCollapse'>
<li parent-id='0' li-id='1'>Parent 1</li>
<li parent-id='1' li-id='2'>Parent 2</li>
<li parent-id='1' li-id='3'>Parent 3</li>
<li parent-id='1' li-id='4'>Parent 4</li>
<li parent-id='3' li-id='5'>Parent c</li>
<li parent-id='3' li-id='6'>Parent d</li>
<li parent-id='2' li-id='7'>Parent a</li>
<li parent-id='4' li-id='8'>Parent b</li>
<li parent-id='4' li-id='9'>Parent e</li>
<li parent-id='5' li-id='10'>Parent x</li>
</ul>
</div>
jQuery
//$('#ulCollapse li').hide();
$('ul li').click(function(){
var nodeId = $(this).attr('li-id');
alert(nodeId);
})
var $ul = $('ul');
$ul.find('li[parent-id]').each(function() {
$ul.find('li[parent-id=' + $(this).attr('li-id') + ']')
.wrapAll('<ul />')
.parent()
.appendTo(this)
});
DEMO
I am not a javascript developer but, tried to solve your problem, here is the working demo
var $ul = $('ul');
$(document).ready(function() {
$ul.find('li[parent-id]').each(function() {
$ul.find('li[parent-id=' + $(this).attr('li-id') + ']').wrapAll('<ul />').parent().appendTo(this)
// not changed its your code still, but I need this only first time, so moved into document ready
});
});
$('ul#category li').click(function() {
$("#ulCollapse1").html(''); // I have created a new div section
$("ul").removeAttr('class'); // remove active classes
var nodeId = $(this).attr('id');
arrangeNodes(nodeId);
$("#ulCollapse1").html($(".active").parent().clone()); //get the marked elements first parent (which is 'li')
$("#ulCollapse").hide(); // hide the main treeview
});
function arrangeNodes(item) {
$ul.find('li[parent-id=' + item + ']').parent().closest("ul").addClass("active"); // find item and mark the first ul as active (selected)
}
Hope helps,
I don't fully understand what you're trying to achieve.
But maybe :lt() is what you're looking for
HTML
<h3>
Category list
</h3>
<ul id='category'>
<li li-id='1' id='1'>Parent 1</li>
<li li-id='2' id='2'>Parent 2</li>
<li li-id='3' id='3'>Parent 3</li>
<li li-id='4' id='4'>Parent 4</li>
<li li-id='5' id='5'>Parent c</li>
<li li-id='6' id='6'>Parent d</li>
<li li-id='7' id='7'>Parent a</li>
<li li-id='8' id='8'>Parent b</li>
<li li-id='9' id='9'>Parent e</li>
<li li-id='10' id='10'>Parent x</li>
</ul>
<br>
<br>
<h3>
Node View
</h3>
<div class='tree'>
<ul id='ulCollapse'>
<li parent-id='1'>
<ul>
<li>Parent 1</li>
</ul>
</li>
<li parent-id='2'>
<ul>
<li>Parent 2</li>
<li>Parent 3</li>
<li>Parent 4</li>
</ul>
</li>
<li parent-id='3'>
<ul>
<li>Parent c</li>
<li>Parent d</li>
<li>Parent a</li>
</ul>
</li>
<li parent-id='4'>
<ul>
<li>Parent b</li>
<li>Parent e</li>
</ul>
</li>
<li parent-id='5'>
<ul>
<li>Parent x</li>
</ul>
</li>
</ul>
</div>
JS
$cats = $("#category");
$tree = $("#ulCollapse");
$tree.children().hide();
$cats.on("click", "li", function() {
var nodeId = $(this).attr('li-id');
console.info("NODE ID: ", nodeId);
$tree.children().hide();
var maxEq = $tree.children("[parent-id='" + nodeId + "']").index();
maxEq < 0 && (maxEq = 0);
maxEq++; //LTE since :lte() doesn't exist
console.info("MAX EQ: ", maxEq);
$tree.children(":lt(" + maxEq + ")").show();
});
FIDDLE ==> https://jsfiddle.net/x45j4fx6/1/

Changing structure of html menu using javascript

CMS, that I am using, generates such a code for menu:
<ul>
<li>second level menu</li>
<li>third level menu</li>
<li>third level menu</li>
</ul>
<ul>
<li>second level menu</li>
<li>third level menu</li>
</ul>
...
I would like to change the way of displaying the third level menu. Is it possible to change this code using javascript into:
<ul>
<li>second level menu
<ul>
<li>third level menu</li>
<li>third level menu</li>
</ul>
</li>
</ul>
<ul>
<li>second level menu
<ul>
<li>third level menu</li>
</ul>
</li>
</ul>
...
You need to differentiate li elements, so you can identify then, which should be first or next level elements. Setting data-attributes, I think is a not "so much bad solution".
Btw, below is only a boilerplate code, and will work verily for given structure. You need to grasp the logic - so you can apply it to other problems.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<ul>
<li data-level="2">second level menu</li>
<li data-level="3">third level menu</li>
<li data-level="3">third level menu</li>
</ul>
<ul>
<li data-level="2">second level menu</li>
<li data-level="3">third level menu</li>
</ul>
<script type="text/javascript">
var uls = document.querySelectorAll('ul');
for(var i=0; i<uls.length; i++) {
var children = uls[i].querySelectorAll("li");
var _children = Array.from(children).filter(e=> e.dataset.level == "3");
if (_children.length > 0) {
var newul = document.createElement("ul");
_children.map(e=>newul.appendChild(e));
uls[i].appendChild(newul);
}
}
</script>
</body>
</html>

Get the size of the parent LI inside an UL?

How can I modify the below code so that I get only the parent li within the first ul and then with another variable get the sub li of the given sub ul?
$(function () {
var vULSize = $("ul li").size();
console.log(vULSize);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li>First</li>
<li>Second
<ul>
<li>Second Sub 1</li>
<li>Second Sub 2</li>
</ul>
</li>
<li>Third</li>
<li>Third
<ul>
<li>Third Sub 1</li>
<li>Third Sub 2</li>
</ul>
</li>
</ul>
Fiddle: http://jsfiddle.net/0sp9pohr/
You can ignore all li's that are descendants of an li like
$(function() {
var vULSize = $("ul li:not(li li)").size();
snippet.log(vULSize);
});
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>First</li>
<li>Second
<ul>
<li>Second Sub 1</li>
<li>Second Sub 2</li>
</ul>
</li>
<li>Third</li>
<li>Third
<ul>
<li>Third Sub 1</li>
<li>Third Sub 2</li>
</ul>
</li>
</ul>
First you need to wrap it all in something, say for instance a div with the id container. Then you can do something like this:
var vULSize = $("#container > ul > li").length;
The > selector gives you only the direct descendants.
If you want to count the number of list elements one level down, this will give you an array with the result:
var counts = $("#container > ul > li").map(function() {
return $(this).find("li").length
}).get();
As pointed out in comments, you should use .length instead of .size().

Creating a menu from a list using Jquery to just show the parent ul and current Level

I've been trying to create a Menu from an list when the current link is identified with a span and I with to display the parent level and the current level on all branches as I navigate through the site. I am fairly new to scripting, any help found be greatly appreciated
Example
If the list was:
A
A b
A b c
A b
And the currentbranch span was on c.
I would want the list to be:
b
b c
b
-HTML List -
<ul>
<li><span class="currentbranch0">Home</span>
<ul class="multilevel-linkul-0">
<li>News
<ul class="multilevel-linkul-1">
<li>Internal
<ul class="multilevel-linkul-2">
<li>Archive</li>
</ul>
</li>
<li>External
<ul class="multilevel-linkul-2">
<li>Archive</li>
</ul>
</li>
<li>News Poll</li>
<li>All News</li>
</ul>
</li>
<li><span class="currentbranch1">Locations</span>
<ul class="multilevel-linkul-1">
<li>a</li>
<li>b</li>
<li>c</li>
<li><span class="currentbranch2">Menu Test</span>
<ul class="multilevel-linkul-2">
<li>test</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Script
(document).ready(function() { var output = '<ul>';
output += $("#side_nav span").last().parent().parent().parent().parent().html();
output += '</ul>';
document.getElementById('side_nav').innerHTML = output;
});$("#side_nav li").ready(function() {
var count = [];
$("#side_nav ul[class^='multilevel-']").each(function(){
var item = $(this).attr('class')
count.push(item);
count.sort();
});
$('#side_nav li').each(function(){
if($(this).parent('ul').hasClass(count[count.length-1])){
$(this).remove();
};
});
});

Categories

Resources