How do I add within the li markup? - javascript

I'm searching how to add a block inside a li markup.
What I have :
<ul>
<li>
<button onclick="expand()">+</button>
Parent 1
</li>
</ul>
What I want after clicking on the button.
<ul>
<li>
<button onclick="expand()">+</button>
Parent 1
<ul>
<li> Child 1</li>
<li> Child 2</li>
</ul>
</li>
</ul>
My expand() function create the children ul with document.createElement() but I don't know how to insert it in the Parent 1 li.

Either insert or toggle or both
$(function() {
$(".expand1").on("click",function(e) {
if ($(this).siblings("ul").length === 0) { // only need to create once
$(this).parent().append(`<ul class="extra">
<li> Child 1</li>
<li> Child 2</li>
</ul>`)
}
$(this).siblings("ul").toggle(); // show or hide
$(this).text($(this).siblings("ul").is(":visible") ? "-":"+"); // change + / -
})
$(".expand2").on("click",function(e) {
$(this).siblings("ul").toggle()
$(this).text($(this).siblings("ul").is(":visible") ? "-":"+")
})
})
.extra { display:none }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
<button type="button" class="expand1">+</button>
Parent 1
</li>
</ul>
<ul>
<li>
<button type="button" class="expand2">+</button>
Parent 1
<ul class="extra">
<li> Child 1</li>
<li> Child 2</li>
</ul>
</li>
</ul>

HTML code
<ul>
<li>
<button onclick="expand(event)">+</button>
Parent 1
</li>
</ul>
Javascript Code
function expand(event) {
var el = event.target.parentElement;
let lastChild = event.target.parentElement.lastChild;
let BeenHere = lastChild.tagName == "UL";
let childLI = document.createElement("li");
let childText = document.createTextNode(`Child ${BeenHere ? lastChild.childElementCount + 1 : 1} `);
childLI.appendChild(childText);
if(BeenHere){
lastChild.appendChild(childLI);
}
else{
let childUL = document.createElement("ul");
el.insertAdjacentElement('beforeend', childUL);
childUL.appendChild(childLI);
}
}

Related

How can I select all the li child of an element in js

How can I select all the li child of an element in js
I want to select all the li elements of this item (direct child, grand child all)
document.querySelectorAll(".stellarnav li.has-sub").forEach(item =>{
item.addEventListener("click", function(){
console.log(item)
// to make you understand I described it below in css language
// in CSS language it is like this: item li
// then I want to removeAttribute from the all the child
// like this
document.querySelectorAll(`${item} li`).forEach(childItem =>{
childItem.removeAttribute("open");
})
// how can I achive this thing to select all the li childs
// here I tried it but this is not valid
})
});```
Just run this.querySelectorAll('li').forEach(li=>li.removeAttribute("open"));
This is a document querySelectorAll document
Tested code:
document.querySelectorAll(".nav li.has-sub").forEach(item =>{
item.addEventListener("click", function(){
this.querySelectorAll('li').forEach(li=>li.removeAttribute("open"));
})
})
li[open]{
color: red;
}
.nav >li{
margin: 10px
}
<ul class='nav'>
<li class='has-sub'>
this is has-sub li 1
<ul>
<li open>
this is open
</li>
<li open>
this is open
</li>
<li> this is another li
</li>
</ul>
</li>
<li class='has-sub'>
this is has-sub li 2
<ul>
<li open>
this is open
</li>
<li open>
this is open
</li>
<li> this is another li
</li>
</ul>
</li>
<li>
this is li 3
<ul>
<li open>
this is not has-sub open
</li>
<li open>
this is not has-sub open
</li>
<li> this is another li
</li>
</ul>
</li>
</ul>

add each class for each parent li in navbar

my html structure is like this
<ul>
<li>items1</li>
<li>items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li>items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li>items4</li>
</ul>
I want to add classes for each parent li like below, using JavaScript is there any possibility to do this?
<ul>
<li class="a">items1</li>
<li class="b">items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li class="c">items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li class="d">items4</li>
</ul>
Using not() filter and addClass(function)
$('li').not('li li').addClass(function(i) {
return String.fromCharCode(i + 97)
})
.a {color:red}
.b {color:orange}
.c {color:green}
.d {color:blue}
li li {color:black}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>items1</li>
<li>items2
<ul>
<li>items2.1</li>
</ul>
</li>
<li>items3
<ul>
<li>items3.1</li>
</ul>
</li>
<li>items4</li>
</ul>
var letters = "abcd";
$("ul").first().children().each(function(index, el)
{
$(el).addClass(letters[index]);
});
Assuming that there could be n number of list items, we can use: String.fromCharCode(97 + index) to get the letter (up to z).
$("ul").first().children("li").each((index, item) => {
const letterFromIndex = String.fromCharCode(97 + index);
let $item = $(item);
$item.addClass(letterFromIndex);
});
If we want add different names for the li u can use this code also
var names = ["ab", "bc", "cd", "de"];
$("ul").first().children().each(function(index, el)
{
$(el).addClass(names[index]);
});

How to target all nested list items beyond a specific level using jquery?

I have a list
<ul>
<li>
<ul>
<li>
<ul>
<li> <-- start targeting list items here including children -->
<ul>
<li> <-- included -->
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
I want to target all list items starting with the second or third nested list including all children thereafter using jquery
var selector = $('ul > li > ul > li > ul li');
The third li has three ul parents. You need to filter li's using .filter() and in it function check length of ul's parent of every li to filtering nested li's.
$("ul:first li").filter(function(){
return $(this).parents("ul").length > 2 ? true : false;
}).css("color", "red");
$("ul:first li").filter(function(){
return $(this).parents("ul").length > 2 ? true : false;
}).css("color", "red");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>First
<ul>
<li>Second
<ul>
<li>Third
<ul>
<li>Fourth</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

Show first level children of a nested ul li using jquery

I have an HTML file like this:
JS:
function functionName(event) {
event.stopPropagation();
var item = event.data.param;
document.getElementById("list").innerHTML = item;
}
$(document).ready(function() {
$("li").each(function() {
$(this).on('click', {param: this.id}, functionName);
});
});
HTML:
<div id="main">
<div id="tree">
<ul class="xyz">
<li class="hide">AVC</li>
<li class="hide">Anna</li>
<li class="hide">Peter</li>
<li id="foo1">Gary
<ul class="xyz">
<li class="hide">John</li>
<li class="hide">Anna</li>
<li id="foo2">Briton
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
<li id="foo3">Layla
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
<li id="foo4">Undertaker
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div id="list"></div>
</div>
I have two div tags whose id is receptively tree and list. Tree div contains the nested ul li tags and each li have unique id.
I want to show the first level children of a ul li tag. For example, when I am clicking on Gary, it should show the first level children ( John, Anna, Britton) in right div i.e. list.
Right now I am able to get the id of ul li element in list div when clicking any item.
How can I traverse the first level children of clicking element using jquery/javascript and display them in list div?
Thanks
Try using find() ,> ul selects the direct descendant
$('li[id^="foo"]').click(function(e){
e.stopPropagation();
var x = $(this).last().find(' > ul').clone().find('ul').remove().end();
console.log(x[0])
$('#list').html(x);
$('#list .hide').show();
});
simple demo : https://jsfiddle.net/sk30mwud/4/
'$('#tree').on('click', 'li', function(){
$(this).find('> ul > li').toggleClass('hide');
return false;
})'
Can you please take a look at this approach:
It uses .contents().get(0).nodeValue to fetch the text present in child li nodes and not from its childerns if any.
function functionName(event) {
event.stopPropagation();
var item = event.data.param;
var names = [];
$("#" + item).children("ul").children("li").each(function() {
names.push($(this).contents().get(0).nodeValue);
});
$("#list").text(names.join(","));;
}
$(document).ready(function() {
$("li").each(function() {
$(this).on('click', {
param: this.id
}, functionName);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="main">
<div id="tree">
<ul class="xyz">
<li class="hide">AVC</li>
<li class="hide">Anna</li>
<li class="hide">Peter</li>
<li id="foo1">Gary
<ul class="xyz">
<li class="hide">John</li>
<li class="hide">Anna</li>
<li id="foo2">Briton
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
<li id="foo3">Layla
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
<li id="foo4">Undertaker
<ul class="xyz">
<li class="hide">gg</li>
<li class="hide">hh</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div id="list"></div>
</div>

How to get the parent LI index and the sub LI index

Fiddle: http://jsfiddle.net/fyrx459k/
Script:
$(function() {
$('.ul1 li').click( function(e) {
e.preventDefault();
var liIndex = $(this).index('li');
console.log(liIndex);
);
});
HTML:
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
How can I modify the script to have the following:
When a parent LI (Test#) is clicked the console will display the index - for example, clicking on Test4 will output a 3 (fourth item)
When clicking on a sub LI (Test# - #) it will display the parent index and the child index - for example, clicking on Test3 - 1 will output 2.0 (2 being the parent LI and 0 being the first child sub LI)
This is one way of doing it:
$(function () {
$('.ul1 li').click(function (e) {
e.preventDefault();
e.stopPropagation();
var i = $(this).parentsUntil('#ul1').add(this).map(function () {
return this.tagName === 'LI' ? $(this).index() : null;
}).get().join('.');
});
});
A pretty basic solution using $(this).parents("li")
$(function() {
$('.ul1 li').click(function(e) {
e.preventDefault();
e.stopPropagation();
var liIndex = "";
var $parents = $(this).parents("li");
if ($parents.length > 0)
liIndex += ($parents.index() + 1) + ".";
liIndex += ($(this).index() + 1);
alert(liIndex);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test
</li>
<li>Test2
</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1
</li>
<li>Test3 - 2
</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1
</li>
<li>Test4 - 2
</li>
</ul>
</li>
</ul>
I love html5 tags, so check if this solution can be useful. Otherwise you can do the same thing with the ID or whatever you prefer.
function checkIndex(element) {
deepCheck(element, '');
}
function deepCheck(element, index) {
if($(element).data('index') && $(element).is('li')) {
var newIndex = '';
if(index.length === 0) {
newIndex = 'Element indexes: ' + $(element).data('index')
} else {
newIndex = index + ' - ' + $(element).data('index');
}
deepCheck($(element).parent(), newIndex);
} else if($(element).data('root')) {
alert(index);
} else {
deepCheck($(element).parent(), index)
}
}
$(document).ready(function() {
$('a').click(function(e) {
e.preventDefault();
checkIndex(this);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul data-root="true" class="ul1" id="ul1">
<li data-index="1">Test</li>
<li data-index="2">Test2</li>
<li data-index="3">Test3
<ul class="ul2">
<li data-index="1">Test3 - 1</li>
<li data-index="2">Test3 - 2</li>
</ul>
</li>
<li data-index="4">Test4
<ul class="ul2">
<li data-index="1">Test4 - 1</li>
<li data-index="2">Test4 - 2</li>
</ul>
</li>
</ul>
Use parents('li') to check if the clicked li has a li ancestor, .index() to determine the index of a li, .preventDefault() to stop the click from following the link and .stopPropagation to stop event from bubbling. This should do it:
$('#ul1 li').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var arr = [];
arr.push( $(this).index() );
!$(this).parents('li').length ||
arr.push( $(this).parents('li').index() );
console.log( arr.reverse().join('.') );
});
$(function() {
$('#ul1 li').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var arr = [];
arr.push( $(this).index() );
!$(this).parents('li').length ||
arr.push( $(this).parents('li').index() );
console.log( arr.reverse().join('.') );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
I would suggest returning false. It removes the need to use both preventDefault and stopPropagation, and also to store the event in e.
Further, some more structured selections would be helpful here. There are only two cases to handle, where a parent element classed ul2 exits and where not. In the case it does, there needs to be two queries to determine the parents index and the current index with regards to the ul2 element. In the case where it does not, then only the relative ul1 index needs to be determined.
I included some extra elements to show the need for a more targeted approach.
$(function(){
$('.ul1 li').click(function() {
var ul2 = $(this).closest('.ul2'),
location = ul2.length > 0 ?
ul2.parent().index('.ul1 > li')+"."+ul2.find('li').index(this) :
$(this).index('.ul1 > li');
log(location);
return false;
});
});
function log(msg){ $("#result").text(msg); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="ul1" id="ul1">
<li>Test</li>
<li>Test2</li>
<li>Test3
<ul class="ul2">
<li>Test3 - 1</li>
<li>Test3 - 2</li>
</ul>
</li>
<li>Test4
<ul class="ul2">
<li>Test4 - 1</li>
<li>Test4 - 2</li>
</ul>
</li>
</ul>
<div id="result"></div>

Categories