How do I use the DOM to modify this? - javascript

How do I modify the style of the li element using DOM?
<div id="tabbed-boosts">
<ul>
<li>test1</li>
<li>test2</li>
<li>test3</li>
</ul>
</div>
getElementById('tabbed-boosts').childNodes will get me to the UL, how do I modify the LI?
Also needs to work in IE6...

var lis = document.getElementById( 'tabbed-boosts' ).getElementsByTagName( 'li' );
for ( var i = 0; i < lis.length; i++ )
{
lis[i].style.backgroundColor = '#' + Math.round( Math.random() * 0xFFFFFF ).toString( 16 );
}

The issue with using document.getElementById( 'tabbed-boosts' ).getElementsByTagName( 'li' ) will show up if you start using nested lists. Using childNodes property will give you access to the direct children of that particular ul element. For example
<ul id='tabbed-boosts'>
<li>...</li>
<li>
<ul>
<li> ... </li>
</ul>
</li>
<li>... </li>
</ul>
using getElementsByTag will return ALL the 'li' elements within tabbed-boosts sub-tree, where childNodes will only return the first level 'li' elements. In the example above you'd receive a collection of 4 elements using getElementById, including the nested LI whereas you would only receive a collection of 3 li elements using myUl.childNodes (shown below)
var myUl = document.getElementById('tabbed-boosts');
var myLi = myUl.childNodes;
for(var i = 0; i<myLi.length; i++)
{
myLi[i].style....;
// do whatever you want to the li items;
}

Related

Can I use a For loop with a Nodelist?

Basically I have some HTML code that is a tree, I was traverse the Nodelist for it and and assign certain classes to nodes if they have children, here's a snippet:
<li id='test' class="parentNode">
<button class="customer-btn button"><a href='#'>Customer 6</a></button>
<ul>
<li>
<a href='#'>Customer A</a>
</li>
</ul>
</li>
<li class="parentNode">
<button class="customer-btn button"><a href='#'>Customer 7</a></button>
<ul>
<li>
<a href='#'> Customer A</a>
</li>
</ul>
</li>
This is my Javascript:
parent_list = document.getElementsByTagName("LI");
var i;
$(document).ready(function() {
for (i=0; i < parent_list.length; i++){
children = $(i).find('LI');
document.getElementById('check').innerHTML = children;
}
});
The for loop I have return [object Object], what's the best what to do this?
You don't need jQuery.
window.addEventListener('DOMContentLoaded', run );
function run() {
var allLIElements = document.getElementsByTagName('LI');
for( var i = 0; i < allLIElements.length; i++ ) {
var li = allLIElements[i];
if( li.firstElementChild != null ) {
li.classList.add('hasChildren');
}
}
}
Note that this will soon be unnecessary as CSS has the proposed :has() pseudo-class which you can use to select elements that meet some criteria.
https://developer.mozilla.org/en-US/docs/Web/CSS/:has
The :has() CSS pseudo-class represents an element if any of the selectors, relative to the:scope of the given element, passed as parameters, matches at least one element. The :has() pseudo-class takes a selector list as an argument.
Consider this style rule instead, it will match any li element that contains another element. No JavaScript required.
li:has(> *) { /* As of early 2017 no browser supports this selector yet! */
}
Since you're using jQuery you don't need a for loop
$('li').each(function(index, element){
if($(element).children().length > 0){
$(element).addClass('myClass')
}
})
You can use a for loop for anything, but your code isn't correct...assigning children to innerHTML isn't a compatible assignment, and doing it in a loop will just result in the element 'check' being assigned multiple times, not with an addition.
If you are using jQuery then use:
$('#check').append(children);

Remove an HTML element depending by it's deep via jQuery

I have nested lists in my HTML page, these lists are managed by a jQuery code which give to the user the interaction of adding rows and children to the list nodes. Every list can contain a div used to add a new list as child.
My problem is I would like to add a dynamic limiter to the deep of the elements I can create:
<ul>
<li>
<ul>
<li><div class="add-child"></div></li>
<li><div class="add-child"></div></li>
<li><div class="add-row"></div></li>
</ul>
</li>
<li><div class="add-child"></div></li>
<li><div class="add-child"></div></li>
<li><div class="add-row"></div></li>
</ul>
The deep could change in the future, I know I can simply use a static selector like this if I want to work with a max of 3 levels of deepness:
$('li li li .add-child').remove();
But I would like a dynamic solution to set the deep via PHP and then limit it via jQuery, how could be my approach to this?
$('.add-child')
.filter(function(){
return $(this).parents('li').length > 2;
})
.remove();
I know, you said you don't need a plugin, but I couldn't resist :D
$.fn.filterIfHasNParents = function(n, selector){
var depth = n || 1;
return $(this).filter(function(){
return $(this).parents(selector || '').length > depth - 1;
});
}
And then use it as :
$('.add-child').filterIfHasNParents(3, 'li').remove();
You mean something like this?
$( '.add-child' ).each( function() {
if( $( this ).parents( 'li' ).length > someDepthSetByPHP )
{
$( this ).remove();
}
} );
jsfiddle example

Splitting an unordered list into multiple divs using jQuery and Javascript

I have an unordered list comprised of little bits of HTML (images, styled text, forms, etc.). The number of items in the list is a variable between 1 and 10. How can I create a pagination system such that all the list items are shown in one DIV if there are 5 or less items, and another DIV is created and filled with the overflow if there are more than 5 items?
For example here is a list with an arbitrary number of elements (in this case, seven):
<ul>
<li><img src="photo.jpg" /></li>
<li><strong>TEXT TEXT TEXT</strong></li>
<li><img src="another_photo.jpg" /></li>
<li><strong>MORE TEXT TEXT TEXT</strong></li>
<li>Say Hello!</li>
<li>MORE STUFF</li>
<li>YET EVEN MORE STUFF</li>
</ul>
And this would be the resulting DIVs
<div id="first_div">
<ul>
<li><img src="photo.jpg" /></li>
<li><strong>TEXT TEXT TEXT</strong></li>
<li><img src="another_photo.jpg" /></li>
<li><strong>MORE TEXT TEXT TEXT</strong></li>
<li>Say Hello!</li>
</ul>
</div>
<div id="second_div">
<ul>
<li>MORE STUFF</li>
<li>YET EVEN MORE STUFF</li>
</ul>
</div>
I think this will get you what you want in pretty short order. It ensures that the two new DIVs land in the DOM where the original UL used to be. It also uses pure jQ selector power rather than loops and counters.
Live Demo: http://jsfiddle.net/JAAulde/3cRZw/1/
Code:
var UL = $( 'ul' ),
upperLIs = UL.find( 'li:gt(4)' ), //get list of LIs above index 4 (above 5th)
DIV1 = $( '<div>' ).attr( 'id', 'first_div' ); //we will definitely need this first DIV
//Get the first DIV into the DOM right before the UL before any movement of UL
//Ensure same DOM placement as we started with
UL.before( DIV1 );
//Check for LIs above index 4
if( upperLIs.length )
{
//Add those LIs to a new UL
//which itself is added to a new DIV
//which itself is added after DIV1
DIV1.after(
$( '<div>' )
.attr( 'id', 'second_div' )
.append(
$( '<ul>' )
.append( upperLIs )
)
);
}
//Move the original UL to DIV1 with it's remaining 5 LIs
DIV1.append( UL );
Edit: edited code to add explanatory comments
Wrap the <ul> in a div. Then grab the last 5 <li> and append them to a new <ul> inside a new <div>:
var ul = $("#myList").wrap($("<div>").attr("id", "first_div"));
$("<div><ul>").attr("id", "second_div").insertAfter("#first_div")
.append(ul.find("li:gt(4)"));
Probably a bit verbose bit this should do it (untested):
$(function() {
var threshold = 5;
// get the original list
var $ul = $("ul");
// create the first container
var $div = $("<div id='first_div'><ul /></div>").appendTo('body');
$("li", $ul).each(function(i) {
if(i < threshold) {
$("ul", $div).append($(this));
}
else {
$overflowDiv = $("#second_div");
// create the second container if it doesn't already exists
if(!$overflowDiv.length) {
var $overflowDiv = $("<div id='second_div'><ul /></div>").appendTo('body');
}
$("ul", $overflowDiv).append($(this));
}
});
// remove the (now empty) list
$ul.remove();
});
var lis=$('ul li');
var divuid=1;
var i=0;
while(lis.length>i){
var lisPart=lis.slice(i,i+4);
i+=4;
$('<div id="div'+(divuid++)+'"></div>').append(lisPart).appendTo($('#my_container'));
}
$('ul li').remove();
shot in the dark, haven't tested it yet... something like this though?

add class to last 2 links from a generate ul list

I have a function that generates a unordered list of links and I want to use javascript to select the last 2 links so that I can align them to the right.
so in the following example I would need to select the li parent of link4 and link5, then add a class so i can style it
<ul>
<li>link1</li>
<li>link2</li>
<li>link3</li>
<li>link4</li>
<li>link5</li>
</ul>
In the end it should be something like this:
<ul>
<li>link1</li>
<li>link2</li>
<li>link3</li>
<li class="align_right">link4</li>
<li class="align_right">link5</li>
</ul>
Couldn't you generate class="align_right" for the last 2 links when you build the list?
By the way, if you want to do this by javascript, you could do:
//get the sidebarmenu element
var sidebar = document.getElementById('sidebarmenu');
//getting the ul inside the wrapper
var ul = sidebar.getElementsByTagName("ul")[0];
//getting al the li childs
var li = ul.getElementsByTagName("li");
var totLi = li.length;
if(totLi >= 2){ //setting class to last 2
li[totLi-1].className = "align_right";
li[totLi-2].className = "align_right";
}
Edit: updated for your particular needs
Running example:
http://www.jsfiddle.net/steweb/m4v2J/
In Jquery:
$('ul li:last-child').prev('li').andSelf().addClass("align_right");
This best be done in the function generating those items, if you insist on client side script afterwards, here it is:
var oList = document.getElementById("myList");
var arrItems = oList.getElementsByTagName("li");
if (arrItems.length >= 2) {
arrItems[arrItems.length - 2].className = "align_right";
arrItems[arrItems.length - 1].className = "align_right";
}
For this to work, add ID to the <ul> tag and use it,

Get all LI elements in array

How can i make JS select every LI element inside a UL tag and put them into an array?
<div id="navbar">
<ul>
<li id="navbar-One">One</li>
<li id="navbar-Two">Two</li>
<li id="navbar-Three">Three</li>
<li id="navbar-Four">Four</li>
<li id="navbar-Five">Five</li>
</ul>
</div>
Can i make it so JS gets each of them into an array eg
navbar['0'] would return document.getElementById("navbar-One")?
You can get a NodeList to iterate through by using getElementsByTagName(), like this:
var lis = document.getElementById("navbar").getElementsByTagName("li");
You can test it out here. This is a NodeList not an array, but it does have a .length and you can iterate over it like an array.
After some years have passed, you can do that now with ES6 Array.from (or spread syntax):
const navbar = Array.from(document.querySelectorAll('#navbar>ul>li'));
console.log('Get first: ', navbar[0].textContent);
// If you need to iterate once over all these nodes, you can use the callback function:
console.log('Iterate with Array.from callback argument:');
Array.from(document.querySelectorAll('#navbar>ul>li'),li => console.log(li.textContent))
// ... or a for...of loop:
console.log('Iterate with for...of:');
for (const li of document.querySelectorAll('#navbar>ul>li')) {
console.log(li.textContent);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<div id="navbar">
<ul>
<li id="navbar-One">One</li>
<li id="navbar-Two">Two</li>
<li id="navbar-Three">Three</li>
</ul>
</div>
QuerySelectorAll will get all the matching elements with defined selector. Here on the example I've used element's name(li tag) to get all of the li present inside the div with navbar element.
let navbar = document
.getElementById("navbar")
.querySelectorAll('li');
navbar.forEach((item, index) => {
console.log({ index, item })
});
<div id="navbar">
<ul>
<li id="navbar-One">One</li>
<li id="navbar-Two">Two</li>
<li id="navbar-Three">Three</li>
<li id="navbar-Four">Four</li>
<li id="navbar-Five">Five</li>
</ul>
</div>
If you want all the li tags in an array even when they are in different ul tags then you can simply do
var lis = document.getElementByTagName('li');
and if you want to get particular div tag li's then:
var lis = document.getElementById('divID').getElementByTagName('li');
else if you want to search a ul first and then its li tags then you can do:
var uls = document.getElementsByTagName('ul');
for(var i=0;i<uls.length;i++){
var lis=uls[i].getElementsByTagName('li');
for(var j=0;j<lis.length;j++){
console.log(lis[j].innerHTML);
}
}
var allElmnts = document.querySelectorAll("ul");
var arr = [];
arr.length = allElmnts.length;
for(var i = 0; i < allElmnts.length; i++){
arr[i] = allElmnts[i];
}

Categories