How to toggle each button separately on multiple li elements? - javascript

I am working on project and my goal is to toggle each individual li element by clicking toggle button.
I managed to do this so far but it's working only on first li element.
Can you help me with this code?
<li id="liEl">Target This element</li>
<button id="Btn">toggle</button>
<li id="liEl" >Target This element</li>
<button id="Btn">toggle</button>
<li id="liEl" >Target This element</li>
<button id="Btn">toggle</button>
.done {
text-decoration: line-through;
text-decoration-thickness: 0.2rem;
text-decoration-color:red;
}
Btn= document.getElementById("Btn");
liEl= document.getElementById("liEl");
const toggleDoneClass = () => {
liEl.classList.toggle('done');
};
Btn.addEventListener('click', toggleDoneClass);

id attribute must be unique.
you can use class instead of that.
HTML
<li class="list_element">Target This element</li>
<button class="btn">toggle</button>
<li class="list_element" >Target This element</li>
<button class="btn">toggle</button>
<li class="list_element" >Target This element</li>
<button class="btn">toggle</button>
You must select all buttons and then add Event Listener to each one by a loop.
Javascript
var btns = document.getElementsByClassName("btn");
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", () => {
// Previous is li because li is before button
btns[i].previousElementSibling.classList.toggle("done");
});
}
Now this is Working.

You are giving the same ids to all the buttons and li instead of id use class names
btns= document.getElementsByClassName("btn");
it will select all the classes which contain buttons
for(let index = 0;index < btns.length; index++){
btns[index].onclick = (evt) =>{
evt.target.previousElementSibling.classList.toggle("done")
}
}
looping all the classes on which you will click it will take that element and then get their previous child which is li and toggle class on that
btns= document.getElementsByClassName("btn");
for(let index = 0;index < btns.length; index++){
btns[index].onclick = (evt) =>{
evt.target.previousElementSibling.classList.toggle("done")
}
}
.done {
text-decoration: line-through;
text-decoration-thickness: 0.2rem;
text-decoration-color:red;
}
<li id="" >Target This element</li>
<button class="btn">toggle</button>
<li id="" >Target This element</li>
<button class="btn">toggle</button>
<li id="lEl" >Target This element</li>
<button class="btn">toggle</button>

IDs should be unique in a page so maybe switch those to classes.
If you want the buttons you should add them within the list item elements.
You can attach one listener to the <ul> element and have that catch events from its children as they "bubble up" the DOM. (This is known as event delegation.)
When a click event is fired you can retrieve the specific element that was clicked with event.target, check that it's a button element, find the closest list item element to that button, and then toggle its class.
const list = document.querySelector('ul');
list.addEventListener('click', toggleDoneClass);
function toggleDoneClass(e) {
if (e.target.matches('button')) {
e.target.closest('li').classList.toggle('done');
}
}
.done { text-decoration: line-through; text-decoration-thickness: 0.2rem; text-decoration-color:red; }
li button { margin-left: 0.5em; }
<ul>
<li class="liEl">
Target This element
<button type="button">Toggle</button>
</li>
<li class="liEl">
Target This element
<button type="button">Toggle</button>
</li>
<li class="liEl">
Target This element
<button type="button">Toggle</button>
</li>
</ul>
But, ultimately, you don't really need the buttons.
const list = document.querySelector('ul');
list.addEventListener('click', toggleDoneClass);
function toggleDoneClass(e) {
if (e.target.matches('li')) {
e.target.classList.toggle('done');
}
}
.done { text-decoration: line-through; text-decoration-thickness: 0.2rem; text-decoration-color:red; }
li:hover { cursor: pointer; }
<ul>
<li class="liEl">Target This element</li>
<li class="liEl">Target This element</li>
<li class="liEl">Target This element</li>
</ul>

Related

How to show a button depending on if there another item in a list?

I'm having problems finding a solution for my code. I asked for help on how to continue click on a list if there's another list inside the list and how to switch between those lists and I've got it to work but the problem I'm having is if the second list is either the last item or if there.
Basically, it looks like this:
<button id="multi-single-next" class="button">Single next</button>
<button id="multi-next-multi-item" class="button">Multi item</button>
<button id="hide" class="button">Hide</button>
<ul class="multi-items">
<li class="single-data-item"><div class="data-item">1</div></li>
<li class="single-data-item"><div class="data-item">2</div></li>
<li class="single-data-item has-multi-items">
<ul class="pagnation-2">
<li>3a</li>
<li>3b</li>
<li>3c</li>
</ul></li>
<li class="single-data-item"><div class="data-item">4</div></li>
<li class="single-data-item"><div class="data-item">5</div></li>
And the way I have it setup is that went the button switches from .multi-items to .pagnation-2, when it gets to the end of that list, it doesn't go back to .multi-items to continue the list.
What would be the best way to check if either the second list (.pagnation-2) is the last item (I.E. no <li> after .pagnation-2) or if the first list continues (I.E. there are <li> after .pagnation-2)?
Here's a working example of my problem:
$('#multi-single-next').click(function() {
let $item;
if(!$('ul.multi-items li.single-data-item.active').length) {
$item = $('ul.multi-items li.single-data-item').first();
}
else {
$prev = $('ul.multi-items li.single-data-item.active');
$item = $prev.next();
if(!$prev.next().length) {
$prev.removeClass('active');
$prev.delay(1).fadeOut(300);
return;
}
$prev.removeClass('active');
$prev.delay(1).fadeOut(300);
}
$item.addClass('active');
$item.delay(300).fadeIn(450);
// sub items
$('ul.pagnation-2 li').removeClass('active');
if($item.hasClass('has-multi-items')) {
const $sub = $item.find('ul li').first();
$sub.addClass('active');
$sub.delay(200).fadeIn(250);
$('#multi-single-next').css('display','none');
$('#multi-next-multi-item').css('display','block');
}
});
$('#multi-next-multi-item').click(function() {
const $item = $('ul.pagnation-2 li.active');
const $next = $item.next();
$item.removeClass('active');
$item.hide();
$next.addClass('active');
$next.show();
});
.multi-items li {
display: inline-block;
list-style: none;
}
.multi-items li:not(:first-child) {
display: none;
}
#multi-next-multi-item {display:none}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="multi-single-next" class="button">Single next</button>
<button id="multi-next-multi-item" class="button">Multi item</button>
<ul class="multi-items">
<li class="single-data-item active"></li>
<li class="single-data-item"><div class="data-item">1</div></li>
<li class="single-data-item"><div class="data-item">2</div></li>
<li class="single-data-item has-multi-items"><ul class="pagnation-2">
<li>3a</li>
<li>3b</li>
<li>3c</li>
</ul></li>
<li class="single-data-item"><div class="data-item">3</div></li>
<li class="single-data-item"><div class="data-item">4</div></li>
</ul>
You can check the length of next li if it does exists.
Solution
$('#multi-next-multi-item').click(function() {
const $item = $('ul.pagnation-2 li.active');
const $next = $item.next();
//Check if last item
const $lastItem = $('ul.pagnation-2 li.active').next().length;
$item.removeClass('active');
$item.hide();
if($lastItem == 0){
//Get the parent
const $li_parent = $item.parent().parent();
const $single_next = $li_parent.next();
$li_parent.removeClass('active');
$li_parent.hide();
$single_next.addClass('active');
$single_next.show();
$('#multi-single-next').css('display','block');
$('#multi-next-multi-item').css('display','none');
}else{
$next.addClass('active');
$next.show();
}
});

How to make the value of li tag hidden using javaScript or Css

I have a list of letters, each one of those letters is inside a li tag :
<ul>
<li class="letter">A</li>
<li class="letter">B</li>
<li class="letter">C</li>
<li class="letter">D</li>
</ul>
The question is how to make those letters (A,B,C,D) hidden without hide the li tag itself, because it already have a style and I don't want to lose it..
and how to make them visible using javaScript function?
PS: the list is created by javaScript function :
var ul = document.createElement('ul');
ul.setAttribute('id','letters');
var txt = txtword.value;
var t, tt;
var word = new Array();
for (i=0;i<txt.length;i++)
word[i] = txt[i];
document.getElementById('answer_div').appendChild(ul);
word.forEach(wordletters);
function wordletters(element, index, arr) {
var li = document.createElement('li');
li.setAttribute('class','item');
ul.appendChild(li);
t = document.createTextNode(element);
li.innerHTML=li.innerHTML + element;
}
Thanks in advance.
<ul>
<li class="letter"><input style="display:none;" type="text" id="A" value="A"></li>
<li class="letter"><input style="display:none;" type="text" id="B" value="B"></li>
<li class="letter"><input style="display:none;" type="text" id="C" value="C"></li>
<li class="letter"><input style="display:none;" type="text" id="D" value="D"></li>
</ul>
You can use to show li data by below function.
function show_li_data(id){
$("#"+id).show();
}
one way to do it you can simply wrap the A,B,C,D inside a span like this
<ul>
<li class="letter"><span>A<span></li>
<li class="letter"><span>B<span></li>
<li class="letter"><span>C<span></li>
<li class="letter"><span>D<span></li>
</ul>
and then
li span{
display:none
}
Here is the the codepen :https://codepen.io/anon/pen/oEmJLP
Consider visibility property:
.letter:nth-child(2) {
visibility: hidden;
}
<ul>
<li class="letter">A</li>
<li class="letter">B</li>
<li class="letter">C</li>
<li class="letter">D</li>
</ul>
Or consider a small width with some oveflow trick if you want to keep the bullet.
li {
list-style:inside;
}
.letter:nth-child(2) {
width:5px;
overflow:hidden;
white-space:nowrap;
}
<ul>
<li class="letter">A</li>
<li class="letter">B</li>
<li class="letter">C</li>
<li class="letter">D</li>
</ul>
Then simply use a class that you can add/remove with JS:
document.querySelectorAll('.letter')[2].classList.add('hide');
li {
list-style:inside;
}
.hide{
width:5px;
overflow:hidden;
white-space:nowrap;
}
<ul>
<li class="letter">A</li>
<li class="letter">B</li>
<li class="letter">C</li>
<li class="letter">D</li>
</ul>
Have modified the answer.Try using text-indent; In your case just add this:
style="text-indent:-9999px;" in each li tag
The solution is :
function wordletters(element, index, arr) {
var li = document.createElement('li');
li.setAttribute('class','item');
ul.appendChild(li);
var span = document.createElement('span');
li.appendChild(span);
span.innerHTML=span.innerHTML + element;
}
This function will create a span inside the li tag, so I can hide the span without hide the li tag ..
Thank you everyone for your time ^_^
You should select this elements by their class name, and set display:none.
document.getElementByClassName("letter").style.display = 'none'
document.getElementByClassName("letter").style.display = 'block'

Dynamic Jquery Code

I am looking for a way to write dynamic codes in Jquery.
Please take a look at these codes below and here is a live sample
Everything works as expected, but Jquery codes repeats and kind of long!
Is there any way to turn this Jquery to dymamic one.
Thanks!
JS
$("#link1").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$(".link1").addClass('red');
});
$("#link2").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$(".link2").addClass('red');
});
$("#link3").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$(".link3").addClass('red');
});
$("#link4").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$(".link4").addClass('red');
});
$("#link5").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$(".link5").addClass('red');
});
HTML
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p>
<button id="link1">link1 Button</button>
<button id="link2">link2 Button</button>
<button id="link3">link3 Button</button>
<button id="link4">link4 Button</button>
<button id="link5">link5 Button</button>
</p>
CSS
.red {
color: red;
}
li {
float:left;
margin-right: 10px
}
p {
float: left;
width: 100%;
margin-top: 50px;
}
button {
corsor: pointer;
}
JS
// a bit more dynamic using a class to capture the click
$(".link").click(function(){
$("#table-filters>ul>li.red").removeClass("red");
$("."+$(this).attr("id")).addClass('red');
});
HTML
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p>
<button class="link" id="link1">link1 Button</button>
<button class="link" id="link2">link2 Button</button>
<button class="link" id="link3">link3 Button</button>
<button class="link" id="link4">link4 Button</button>
<button class="link" id="link5">link5 Button</button>
</p>
Sure, you can use .each() to iterate through nodes and dynamic selector to set the class for necessary element. Here is jsfiddle: http://jsfiddle.net/kG2AZ/189/
And the snippet:
$("button").each(function(i, item) {
$(item).click(function() {
$("#table-filters>ul>li.red").removeClass("red");
$(".link"+(i+1)).addClass('red');
});
});
.red {
color: red;
}
li {
float: left;
margin-right: 10px;
list-style: none;
}
p {
float: left;
width: 100%;
margin-top: 50px;
}
button {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p id="buttons">
<button id="link1">link1 Button</button>
<button id="link2">link2 Button</button>
<button id="link3">link3 Button</button>
<button id="link4">link4 Button</button>
<button id="link5">link5 Button</button>
</p>
Because your button's ids and link's classes name are same, so you can use them to add or remove the red class in the links.
Stack Snippet
$('#buttons button').on('click', function() {
$('#table-filters ul>li').removeClass('red');
$('#table-filters ul>li[class="' + $(this).attr('id') + '"]').addClass('red');
})
.red {
color: red;
}
li {
float: left;
margin-right: 10px;
list-style: none;
}
p {
float: left;
width: 100%;
margin-top: 50px;
}
button {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p id="buttons">
<button id="link1">link1 Button</button>
<button id="link2">link2 Button</button>
<button id="link3">link3 Button</button>
<button id="link4">link4 Button</button>
<button id="link5">link5 Button</button>
</p>
I'd suggest the following approach:
// select all elements with an 'id' attribute whose value
// begins with 'link':
$('button[id^=link]')
// bind the anonymous function of the on() method as
// as the event-handler for the 'click' event:
.on('click', function() {
// finding the <li> elements with a class equal to the
// id of the clicked <button> element, contained within
// the #table-filters element:
$('#table-filters li.' + this.id)
// add the 'red' class to that element:
.addClass('red')
// select the siblings of that <li> element:
.siblings()
// remove the 'red' class from those sibling <li> elements:
.removeClass('red');
});
$('button[id^=link]').on('click', function() {
$('#table-filters li.' + this.id).addClass('red').siblings().removeClass('red');
});
.red {
color: red;
}
li {
float: left;
margin-right: 10px;
list-style-type: none;
}
p {
float: left;
width: 100%;
margin-top: 50px;
}
button {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p>
<button id="link1">link1 Button</button>
<button id="link2">link2 Button</button>
<button id="link3">link3 Button</button>
<button id="link4">link4 Button</button>
<button id="link5">link5 Button</button>
</p>
This is also possible using plain JavaScript:
// defining a function to handle the 'highlight' functionality:
function highlight() {
// using Array.from() to convert the nodeList returned from
// document.querySelectorAll() into an Array:
Array.from(
// finding all the <li> elements within the
// #table-filters element:
document.querySelectorAll('#table-filters li')
// iterating over that Array of nodes using
// Array.prototype.forEach():
).forEach(
// 'link' is a reference to the current node of the Array
// of Nodes over which we're iterating;here we access the
// Element.classList property, and use a ternary operator
// to determine whether we should use the 'add()' or
// 'remove()' method:
link => link.classList[
// if the classList of the current node ('link') contains
// a class equal to the id attribute of the clicked (this)
// <button> we return the 'add' function-name, otherwise
// we return the 'remove' function-name (using the square-
// bracket syntax to access properties of the current
// Object):
link.classList.contains(this.id) ? 'add' : 'remove'
// we pass the 'red' string as an argument:
]('red')
)
}
// using Array.from() to convert the nodeList returned by
// document.querySelectorAll() into an Array:
Array.from(
// here we find all <button> elements with an 'id' attribute
// whose attribute-value starts with 'link':
document.querySelectorAll('button[id^=link]')
// iterating over the Array of nodes:
).forEach(
// 'button' is a reference to the current node of the
// Array of nodes over which we're iterating; here
// we use the EventTarget.addEventListener() function
// to bind the named function ('highlight') as the event-
// handler for the 'click' event:
button => button.addEventListener('click', highlight)
);
function highlight() {
Array.from(
document.querySelectorAll('#table-filters li')
).forEach(
link => link.classList[link.classList.contains(this.id) ? 'add' : 'remove']('red')
)
}
Array.from(
document.querySelectorAll('button[id^=link]')
).forEach(
button => button.addEventListener('click', highlight)
);
.red {
color: red;
}
li {
float: left;
margin-right: 10px;
list-style-type: none;
}
p {
float: left;
width: 100%;
margin-top: 50px;
}
button {
cursor: pointer;
}
<div id="table-filters">
<ul>
<li class="link1">link 1</li>
<li class="link2">link 2</li>
<li class="link3">link 3</li>
<li class="link4">link 4</li>
<li class="link5">link 5</li>
</ul>
</div>
<p>
<button id="link1">link1 Button</button>
<button id="link2">link2 Button</button>
<button id="link3">link3 Button</button>
<button id="link4">link4 Button</button>
<button id="link5">link5 Button</button>
</p>
References:
CSS:
Attribute selectors.
JavaScript:
Array.from().
Array.prototype.forEach().
Arrow function syntax.
Element.classList API.
EventTarget.addEventListener().
jQuery:
addClass().
on().
removeClass().
siblings().

How to add a class to a clicked <li> and remove this class from its siblings using Javascript?

I have some <li> elements inside <ul> element in the navigation bar , There is a class called "active" that has some properties to define the active page , I want to add this class to one of them when it is clicked and remove it from this <li> siblings using Javascript without any frameworks just pure Javascript .
<ul class='tabs'>
<li class='active'>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
So when another page name is clicked the 'active' class is removed from the others and added to that page name.
Try the code below:
[].forEach.call(document.querySelectorAll('.tabs li'), function(el) {
el.addEventListener('click', function(e) {
var activeItem = document.querySelector(".tabs li.active");
if(activeItem)
{
activeItem.classList.remove("active");
}
el.classList.add("active");
});
});
code edited in case you don't have any initial active items
A list of link nodes can be selected using document.querySelector and an event listener attached for click events.
const links = document.querySelectorAll('.tabs li');
function activate(links) {
links.forEach(function(link) {
link.classList.remove('active');
});
this.classList.add("active");
}
links.forEach(function(link) {
link.addEventListener('click', activate.bind(link, links));
});
.active {
color: red;
}
<ul class='tabs'>
<li class='active'>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
This would be the most efficient way to do it using only 1 event listener on the parent UL:
document.querySelector('.tabs').addEventListener('click', function(e) {
var current = e.target; // the item clicked
// all li items
var items = current.parentElement.querySelectorAll('li');
// go through each li and remove .active unless current
Array.prototype.slice.call(items).forEach(function (item) {
item.className = (item === current) ? 'active' : '';
});
});
.active {
color: red;
}
<ul class='tabs'>
<li class='active'>Home</li>
<li>About</li>
<li>Contact</li>
</ul>

How to hide parent <li> if all the children are hidden in jquery

I am new in Jquery
My Webpage structure is like this
<div id="MenuSection">
<ul>
<li>Master // Main Menu
<ul>
<li>Master1</li>
<li>Master2</li>
<li>Master3</li>
</ul>
</li>
<li>Transaction // Main Menu
<ul>
<li>Transaction1</li>
<li>Transaction2</li>
<li>Transaction3</li>
</ul>
</li>
<li>Report // Main Menu
<ul>
<li>Report1</li>
<li>Report2</li>
<li>Report3</li>
</ul>
</li>
</ul>
</div>
I want that when all the children of any Parent(main menu) are hidden, Parent should also be hidden. Let's say if Report1, Report2, Report3 are hidden then Parent that is "Report" should also be hidden.
How can I achieve this through Jquery ?
One way is to iterate over each main menu li to see if its children are all :visible:
$("#MenuSection>ul>li").each(function() {
if ($(this).find(">ul>li:visible").length == 0) {
$(this).hide();
}
});
there are other ways to do this, such as using .filter or .map, but this should get you what you need.
Given the nested ul's the above uses > to ensure only the directly ul>li children are processed. If you have multiple levels, you might need to change accordingly, eg for the first: #MenuSection li would apply to all lis and the second .find(">ul>li:visible") only looks at direct li children.
$("#MenuSection>ul>li").each(function() {
if ($(this).find("li:visible").length == 0) {
$(this).hide();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="MenuSection">
<ul>
<li>Master
<ul>
<li>Master1</li>
<li>Master2</li>
<li>Master3</li>
</ul>
</li>
<li>Transaction
<ul>
<li>Transaction1</li>
<li>Transaction2</li>
<li>Transaction3</li>
</ul>
</li>
<li>Report
<ul>
<li style='display:none'>Report1</li>
<li style='display:none'>Report2</li>
<li style='display:none'>Report3</li>
</ul>
</li>
</ul>
</div>
JavaScript does it fairly easy. You would need expand on this to execute this check every on the relevant list every time you hide or show a list item.
function isHidden(array) {
for(var i = 0; i < array.length - 1; i++) {
if(array[i+1].style.display != "none") {
return false;
};
};
return true;
};
var children = document.getElementById("report").getElementsByTagName("LI");
if (isHidden(children)) {
document.getElementById("report").style.display = "none";
};
You can use the the .is(':visible')
See the code:
(function($) {
$(document).ready(function() {
var $mainLinks = $('#MenuSection > ul > li');
$.each($mainLinks, function() {
if (!$(this).find('li').is(':visible')) {
$(this).hide();
}
});
});
})(jQuery);
#MenuSection > ul > li:last-child li {
display: none;
}
#MenuSection > ul > li:first-child li:first-child {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="MenuSection">
<ul>
<li>Master // Main Menu
<ul>
<li>Master1</li>
<li>Master2</li>
<li>Master3</li>
</ul>
</li>
<li>Transaction // Main Menu
<ul>
<li>Transaction1</li>
<li>Transaction2</li>
<li>Transaction3</li>
</ul>
</li>
<li>Report // Main Menu
<ul>
<li>Report1</li>
<li>Report2</li>
<li>Report3</li>
</ul>
</li>
</ul>
</div>

Categories

Resources