Making each li of a Ul clickable - javascript

I have a simple ul list, as can be seen below:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
What I want to do, is to make this list clickable. So that when you click on one of the Lis, the background color changes, and the selected li will also be assigned a new class.
My JS code isn't working:
var ul = document.getElementById("foo")
var items = ul.getElementsByTagName("li")
for (var i = 0; i < items.length; ++i) {
// do something with items[i], which is a <li> element
var current = items[i]
current.addEventListener("click", onClick)
var onClick = function() {
current.style.backgroundColor = "red"
}
}

HTML:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
CSS:
.backgroundColor {
background-color: lightgray;
}
JS:
var items = document.getElementsByTagName("li")
items.forEach(li => {
li.addEventListener('click', () => {
li.classList.toggle('backgroundColor');
});
});
Hopefully this will help you to solve your problem.

Try something like this:
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul id="list">
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>
<script>
document.getElementById("list").addEventListener("click",function(e) {
if (e.target && e.target.matches("li")) {
e.target.classList.toggle("foo"); // toggle foo class name here
e.target.style.backgroundColor = "red"; // new background color here
}
});
</script>
I assigned your ul element an id of "list" and added a "click" event listener to it. Whenever you click an li element within that list, it will assign the foo class to that clicked element (click again to unassign). Similarly, assign a red background color to that element.
JavaScript - addEventListener on all created li elements

I hope my code solved your problem.
$(document).ready(()=>{
$(".my-list li").each((i)=>{
var myLi = $($(".my-list li")[i]);
myLi.bind("click",()=>{
if(!myLi.hasClass("selected"))
myLi.addClass("selected")
else
myLi.removeClass("selected")
})
})
})
.selected{
background-color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="my-list">
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>

See below. Documentation is inside the code.
// Put a nodelist of li's in variable lis
const lis = document.querySelectorAll("ul li");
// Add an event listener to each li
lis.forEach(li => {
li.addEventListener("click", () => {
// Remove class selected from currently selected li
document.querySelector("ul li.selected").classList.remove("selected");
// Assign class selected to the clicked li
li.classList.add("selected");
});
});
li {
cursor: pointer; /* Change cursor */
}
li.selected {
/* Change background color of selected li */
background-color: lightgreen;
}
<div class="container">
<div class="row">
<div class="col">
<h1>My Favorite Meals <span>(1)</span></h1>
<hr>
<ul>
<li class="selected">Spaghetti</li>
<li>Curry & Rice</li>
<li>Burrito</li>
<li>Soup</li>
<li>Something Else</li>
</ul>
</div>
</div>
</div>

Related

Child element effecting open/close toggle

I have created code for an open/close toggle filter by targeting the first li of the filter. For some reason, the children li's that are nested inside this are also closing the toggle when selected to filter the feed.
Please would someone be able to advise how to only target the parent li without the children li affecting the toggle from opening and closing?
Here is a link to the page with the filter. Please test the toggle and select a filter to see the issue that I am currently facing.
https://snapstaging.co.uk/coolkitnew/vans/
It may be worth noting that I don't want to target by class because I have multiple of these elements all with different classes.
let filterBlock = document.querySelectorAll('.searchandfilter li ul')
let filterLi = document.querySelectorAll('.searchandfilter ul li')
let filterLiOpen = [];
filterLi.forEach((tag, index) => {
tag.addEventListener('click', () => {
filterLi[index].classList.toggle('active')
if (!filterLiOpen[index]) {
filterLiOpen[index] = true;
} else if (filterLiOpen[index]) {
filterLiOpen[index] = false;
}
console.log(filterLiOpen);
})
})
.active { color: #C00; }
<div class="searchandfilter">
<ul>
<li class="sf-field-post-meta-vehicle_size">
<h4>Size</h4>
<ul data-operator="and" class="">
<li class="sf-level-0"><label class="sf-label-checkbox">Large Van<span class="sf-count">(20)</span></label></li>
</ul>
</li>
</ul>
</div>
The issue is because you select all the li elements in the DOM. To target only those which are children of the top level ul, not its descendants, use the child operator in your selector: >.
Also note that you can simplify the logic which toggles the boolean value you store in your array. Here's a working example:
let filterLi = document.querySelectorAll('.searchandfilter > ul > li')
let filterLiOpen = [];
filterLi.forEach((tag, index) => {
tag.addEventListener('click', e => {
e.currentTarget.classList.toggle('active');
filterLiOpen[index] = !filterLiOpen[index];
console.log(filterLiOpen);
})
})
.active { color: #C00; }
<div class="searchandfilter">
<ul>
<li class="sf-field-post-meta-vehicle_size">
<h4>Size</h4>
<ul data-operator="and" class="">
<li class="sf-level-0">
<label class="sf-label-checkbox">
Large Van
<span class="sf-count">(20)</span>
</label>
</li>
</ul>
</li>
<li class="sf-field-post-meta-vehicle_size">
<h4>Size</h4>
<ul data-operator="and" class="">
<li class="sf-level-0">
<label class="sf-label-checkbox">
Medium Van
<span class="sf-count">(10)</span>
</label>
</li>
</ul>
</li>
<li class="sf-field-post-meta-vehicle_size">
<h4>Size</h4>
<ul data-operator="and" class="">
<li class="sf-level-0">
<label class="sf-label-checkbox">
Small Van
<span class="sf-count">(5)</span>
</label>
</li>
</ul>
</li>
</ul>
</div>

How can I loop through a string array and only get the value of the data attribute that is clicked on

I am trying to get from the <ul class="click-to-section"> to the tester class where I want to loop over the children that has data-section and only show it if it matches up with the <ul class="click-to-section">
See the screenshot of the HTML from Google Dev tools - https://ibb.co/Y3g1jmC
my code to show this is below:
$(".click-to-section li").click(function() {
$(this).each(function(){
let testdata = $(this).data('section');
let testdata2 = $(this).closest("main").next().next().children();
$(testdata2).each(function(){
const dataSection = $(this).data("section");
console.log(dataSection);
});
});
});
HTML
<ul class="click-to-section">
<li data-section="videos">Videos</li> **When this is clicked**
<li data-section="lo">Learning objectives</li>
<li data-section="credits">Credit</li>
<li data-section="toolkits">Toolkit</li>
</ul>
<div class="opinions"></div>
<div class="tester"> **Needs to traverse to this div and loop through the children to show the sections one at a time based on the data-section in the ul menu to equal the data-section here **
<div data-section="credits" class="js-tabs" style="display: none;"</div>
<section data-section="videos" class="js-tabs"></section>
<div class="js-tabs" data-section="lo" style="display: none;"></div>
<div data-section="toolkits" class="js-tabs" style="display: none;"></div>
</div>
Updated the code to click on li and show tester elements that matches data attributes of clicked li
Working Code below
$(".click-to-section li").on("click", function() {
var dataSection = $(this).attr("data-section");
$(".tester > *").hide();
$(".tester [data-section=" + dataSection + "]").show();
})
li {
cursor: pointer
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="click-to-section">
<li data-section="videos">Videos</li> **When this is clicked**
<li data-section="lo">Learning objectives</li>
<li data-section="credits">Credit</li>
<li data-section="toolkits">Toolkit</li>
</ul>
<div class="opinions"></div>
<div class="tester">
<div data-section="credits" class="js-tabs">cred </div>
<section data-section="videos" class="js-tabs">video</section>
<div class="js-tabs" data-section="lo">lo</div>
<div data-section="toolkits" class="js-tabs">js tabs</div>
</div>

Switching between three classes with different names

I have a header and three different classes defines three different sizes. On click of the different buttons I need to apply the size class to the header and remove the existing heading size class.
JS Fiddle
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader">S</a></li>
<li class="list-inline-item"><a id="mediumHeader">M</a></li>
<li class="list-inline-item"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
jQuery:
this.$('.list-inline-item').click(function() {
if ($('.layout-attachments h1').hasClass('w-50-p')) {
$('.layout-attachments h1').removeClass('w-50-p').addClass('w-75-p ');
} else if ($('.layout-attachments h1').hasClass('w-75-p ')) {
$('.layout-attachments h1').removeClass('w-75-p ').addClass('w-100-p');
} else if ($('.layout-attachments h1').hasClass('w-100-p')) {
$('.layout-attachments h1').removeClass('w-100-p').addClass('w-50-p');
}
});
});
This is very easy. Here i made an example.
Make sure to read the comment and also have a look at attribute Size
var sizes= ["w-75-p", "w-100-p", "w-50-p" ]
$('.list-inline-item').click(function() {
sizes.forEach((item)=> $('.layout-attachments h1').removeClass(item) ); // reset the size.
// now Add the right Size
$('.layout-attachments h1').addClass($(this).attr("size"))
});
.w-50-p {
font-size: 18px;
}
.w-75-p {
font-size: 26px;
}
.w-100-p {
font-size: 34px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item" size="w-50-p"><a id="smallHeader">S</a></li>
<li class="list-inline-item" size="w-75-p"><a id="mediumHeader">M</a></li>
<li class="list-inline-item" size="w-100-p"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>
There are a couple of issues with your code. For starters, you have a syntax error in your jQuery block. You also don't need spaces after your class names in the removeClass calls. But the biggest issue is you need to be able to determine if the user has clicked "small", "medium", or "large" in order to apply the correct class. Otherwise, if you make the other corrections I mentioned, as it is right now you will basically just be toggling through the three classes.
Here's how I might approach the problem, with click handlers for each of the list elements (small, medium, large):
this.$('.list-inline-item').click(function(e) {
if (e.target.id === "smallHeader") {
// handle small case
$(".layout-attachments h1").removeClass("w-75-p w-100-p").addClass("w-50-p");
} else if (e.target.id === "mediumHeader") {
// handle medium case
$(".layout-attachments h1").removeClass("w-50-p w-100-p").addClass("w-75-p");
} else if (e.target.id === "largeHeader") {
// handle large case
$(".layout-attachments h1").removeClass("w-50-p w-75-p").addClass("w-100-p");
} else {
// unhandled case
}
});
.w-50-p {
font-size: 18px;
}
.w-75-p {
font-size: 26px;
}
.w-100-p {
font-size: 34px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader">S</a></li>
<li class="list-inline-item"><a id="mediumHeader">M</a></li>
<li class="list-inline-item"><a id="largeHeader">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>
Another thing you could do, instead of calling removeClass with the other classes you don't want attached to the element, is add a function to jQuery that will remove all classes according to some substring. For example, with this function, you could remove all classes starting with "w-":
$.fn.removeClassStartingWith = function (filter) {
$(this).removeClass(function (index, className) {
return (className.match(new RegExp("\\S*" + filter + "\\S*", 'g')) || []).join(' ')
});
return this;
};
You could invoke it then like this:
$(".layout-attachments h1").removeClassStartingWith("w-").addClass("w-50-p");
This is not absolutely necessary but might be useful.
You had some errors in your jQuery:
$('.list-inline-item').on('click', function() {
if ($('.layout-attachments h1').hasClass('w-50-p')) {
$('.layout-attachments h1').removeClass('w-50-p').addClass('w-75-p');
} else if ($('.layout-attachments h1').hasClass('w-75-p')) {
$('.layout-attachments h1').removeClass('w-75-p ').addClass('w-100-p');
} else if ($('.layout-attachments h1').hasClass('w-100-p')) {
$('.layout-attachments h1').removeClass('w-100-p').addClass('w-50-p');
}
});
But either way the code doesn't make much sense as it is, because it doesn't matter what li item you click.
Edit:
html:
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item" data-size="w-50-p"><a id="smallHeader">S</a></li>
<li class="list-inline-item" data-size="w-75-p"><a id="mediumHeader">M</a></li>
<li class="list-inline-item" data-size="w-100-p"><a id="largeHeader">L</a></li>
</ul>
<h1 id="w-75-p" class="img-responsive img-thumbnail">Change the class of this element</h1>
</div>
</div>
jQuery:
$('.list-inline-item').on('click', function() {
var newSize = $(this).attr("data-size");
$(".layout-attachments h1").removeAttr("id").attr("id", newSize)
});
css:
#w-50-p {font-size: 18px;}
#w-75-p {font-size: 26px;}
#w-100-p {font-size: 34px;}
The easiest was is to use an id on the target element and set a data attribute which refers to the correct id.
You can do this:
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a id="smallHeader" data-new-class="w-50-p">S</a></li>
<li class="list-inline-item"><a id="mediumHeader" class="active" data-new-class="w-75-p">M</a></li>
<li class="list-inline-item"><a id="largeHeader" data-new-class="w-100-p">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>
</div>
there is an class="active" and data-new-class="w-75-p" that track what is currently clicked and what class to apply when click. You can find a better name for the data attribute.
For javascript:
$('.list-inline-item a').click(function() {
var $activeSize = $('.list-inline-item a.active');
// removes active from current
$activeSize.removeClass('active');
var $heading = $('.layout-attachments h1')
//removes the class and add class you want
$heading.removeClass($activeSize.data('newClass'));
$heading.addClass($(this).data('newClass'));
//add active to the clicked one
$(this).addClass("active")
});
JS Fiddle
Maintain the class which alters the font size in the list item as a data attribute and add the new class to the target on click event!
Here is the working solution..
var $item = $('.list-inline-item'),
$target = $('.img-responsive.img-thumbnail');
$item.on('click', function() {
var size = $(this).find('a').data('size');
$target
.removeClass('w-50-p w-75-p w-100-p') // remove size classes
.addClass(size);
});
.w-50-p {
font-size: 1em;
}
.w-75-p {
font-size: 1.5em;
}
.w-100-p {
font-size: 2em;
}
.list-inline-item a {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-12">
<div class="layout-attachments">
<ul class="list-inline layout-components">
<li class="list-inline-item"><a data-size="w-50-p">S</a></li>
<li class="list-inline-item"><a data-size="w-75-p">M</a></li>
<li class="list-inline-item"><a data-size="w-100-p">L</a></li>
</ul>
<h1 class="img-responsive img-thumbnail w-75-p">Change the class of this element</h1>
</div>

Javascript change effect for <ul><li> is not working correctly

I am new to Javascript. I want to click on the Navi bar to change some effect(underline to the words)
Coding for HTML
<div class="nav" id="nav">
<ul>
<li>Home</li>
<li>text1</li>
<li>text2</li>
</ul>
</div>
<div id="text1"> <!--> jump to here<-->
.....
</div>
<div id="text2"> <!--> jump to here<-->
.....
</div>
<script>
function SetTabState(dom){
$("#nav ul li").find('.underline_text').removeClass('underline_text');
$(dom).addClass('underline_text');
}
</script>
Just like the screenshot, when clicking "text1" tab, the home underline is removed and "text1" underline is added...
However, for my coding, when clicking on "text1", the underline is not changing and remain at "home". Anyone knows the problem here? Thx!
This is because from your html
<a href="index.html#text2" onclick="SetTabState(this)">
this refer to <a>, so dom is actually an <a>
From your SetTabState(dom), dom suppose to be a <li>?
You can add a event delegation to the <ul> with delegate to the <li>, like
function SetTabState(dom) {
$("#nav ul li").find('.underline_text').removeClass('underline_text');
$(dom).addClass('underline_text');
}
$(document).ready(function() {
$("#nav ul").on('click', 'li', function() {
SetTabState(this)
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav" id="nav">
<ul>
<li>Home</li>
<li>text1</li>
<li>text2</li>
</ul>
</div>
<div id="text1">
<!-->jump to here
<-->
.....
</div>
<div id="text2">
<!-->jump to here
<-->
.....
</div>
As others have said, the dom variable refers to the <a> element, but you're trying to remove the class from the <li>. Instead of using .find, you can directly select the element with the underline_text class:
<script>
function SetTabState(dom){
$("#nav ul li .underline_text").removeClass('underline_text');
$(dom).addClass('underline_text');
}
</script>
You can do like this :-
function SetTabState(dom){
$("#nav ul li a").removeClass('underline_text');
$(dom).addClass('underline_text');
}
ul {
padding: 0;
margin: 0;
list-style: none;
}
ul li a {
text-decoration: none;
}
ul li a.underline_text {
border-bottom: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav" id="nav">
<ul>
<li>Home</li>
<li>text1</li>
<li>text2</li>
</ul>
</div>
Because you need to change the state of the other elements rather than the only element you clicked, I suggest you use a function for the whole group of elements instead of handle click event on each element. This is my code:
function initClickableNav(nav) {
var navItems = nav.querySelectorAll('a');
var activeClass = 'underline_text';
nav.addEventListener('click', function (event) {
[].forEach.call(navItems, function (navItem) {
if (navItem === event.target || navItem.contains(event.target)) {
navItem.classList.add(activeClass);
} else {
navItem.classList.remove(activeClass);
}
});
});
}
initClickableNav(document.querySelector('#nav'));
HTML
<div class="nav" id="nav">
<ul>
<li><span>Home</span></li>
<li>text1</li>
<li>text2</li>
</ul>
</div>

How to change colour of an element nested in other elements using javascript

I have a list structured as such:
<ul class="list">
<li class="list-element ">
<a href="#"><a>
</li>
</ul>
<button onclick="changeColour()"></button>
<script src="js/index.js"></script>
The css for my links are:
ul li a {
color: red
{
How do I change the colour of my links?? I know you can do this:
function changeColour() {
var div = document.getElementsByTagName("ul");
div.style.changeColour = "rgb(0, 212, 177)";
}
but I don't know how to the links within list item within the list.
Try document.querySelectorAll:
let links = document.querySelectorAll("ul.list li.list-element a");
for (let link of links) {
link.style.color = "rgb(0, 212, 177)";
}
ul li a {
color: red
{
<ul class="list">
<li class="list-element">
LINK 1
</li>
<li class="list-element">
LINK 2
</li>
</ul>
You can change it with css. Your css is correct but you missed ; after red. And you can do it with javascript too or you can use both if you want to give it a color then change it at run time. For your javascript code you forgot to add the collection's index...
document.getElementsByTagName('a')[0].style.color='orange';
NB: I'm targeting the first anchor with [0]. To target all anchors loop through the collection.
Like this
function changeColour() {
var div = document.getElementsByTagName("a");
for(var i = 0; i < div.length; i++){
div[i].style.color = "rgb(111, 112, 112)";
}
}
changeColour();
ul li a {
color: red;
{
<ul class="list">
<li class="list-element ">
<a href="#">link 1<a>
</li>
<li class="list-element ">
<a href="#">link 2<a>
</li>
</ul>
HTML
<ul class="list">
<li class="list-element ">
<a href="#">link 1<a>
</li>
<li class="list-element ">
<a href="#">link 2<a>
</li>
</ul>
Script
$('.list').each(function(){
$(this).find('li a').css('color','rgb(111, 112, 112)');
});
Below is Jquery model in case you are looking for it
// Jquery model if you want to use
$(document).ready(function(){
$('#change').click(function(){
var color=["blue","red","yellow","black","pink","green"];
var prompts = prompt("please type your valid color");
// checking if entered colored is registered
for(x in color){
if(color[x] ==prompts){
//registered then set its value as color
$("a").css({"color":prompts});
return ;
}
}
// deal with unregistered color
var conf = confirm('not registered color entered , do you want to set the default color?');
if(conf ==true ){
$("a").css({"color":"black"});
}
});
});
ul li a {
color: red;
{
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li class="list-element ">
link 1
</li>
<li class="list-element ">
link 2
</li>
</ul>
<p id='change'> please click here to change link color </p>

Categories