Toggle class between list elements on click of a button - javascript

I need to remove and add a class between elements of a list, if I hit the #swapThumb button it should remove the selected class from the current element and then added to the next element.
Here's what I have
html
<ul id="product-thumbnails" class="thumbnails list-inline">
<li class="vtmb vt-123 selected" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-456" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-789" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-101" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-121" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
</ul>
<button id="swapThumb">Next</button>
javascript
let thumbsNailsList = $('#product-thumbnails').find('li');
let swapButton = $('#swapThumb');
thumbsNailsList.each((index, item) => {
let thumbsAvailable = $(item).attr('style');
if (thumbsAvailable === '') {
$(swapButton).on('click', () => {
$(item).removeClass('selected');
$(item).closest($(item)).next().addClass('selected');
});
}
});
First I'm checking if the li element has an empty style attribute (this is needed), if so, trigger the click validation.
The click should remove the selected class from the first element and then added to the next one and so on (it should match the empty style attribute). Once the selected class hits the last element of the list it should return the class to the first element.

This code snippet will change the class of the element beneath it to selected and remove it from the current one, while keeping all the other classes. It will also loop back to the beginning element if next is clicked when on the last element. I've heard jQuery functions are more expensive that document functions and shouldn't be used for these kinds of things. Apply this to your problem and you should get the expected result
let i = 0;
let thumbsNailsList = document.getElementById("product-thumbnails").children;
let btn = document.getElementById("btn");
btn.onclick = function() {
var prevClasses = thumbsNailsList[i].className;
thumbsNailsList[i].className = prevClasses.replace("selected", "");
i = (i+1) % thumbsNailsList.length;
thumbsNailsList[i].className = "selected";
console.log(thumbsNailsList);
}
<ul id="product-thumbnails">
<li class='selected'></li>
<li class=''></li>
<li class=''></li>
<li class=''></li>
</ul>
<button id="btn">Next</button>

Related

Toggling class on targeted element and removing class from siblings

I'm having trouble getting a class to properly toggle on the clicked element while removing the same class from siblings. The below code works as expected except when you click an element that has the active class already. For example, when you click one of these li elements it will get the active class and the active class will also get removed from its siblings. However, if an element already has the active class, any additional clicks to that element will not remove the active class.
Javascript
const topUI = document.querySelectorAll('.top-left-icons ul li');
topUI.forEach(li => {
li.addEventListener('click', e => {
[...li.parentElement.children].forEach(sib => sib.classList.remove('active'))
li.classList.toggle('active');
})
})
HTML
<div class="top-left-icons menu">
<ul>
<li id="home">
<img src="images/home-outline.png">
</li>
<li id="information">
<img src="images/information-outline.png">
</li>
<li id="full-screen">
<img src="images/full-screen-outline.png">
</li>
<li id="air-flow">
<img src="images/air-flow-outline.png">
</li>
<li id="contact">
<img src="images/contact-outline-person.png">
</li>
</ul>
</div>
The forEach() loop removes the class from all the elements, including the one you clicked on. Then you toggle the element that was clicked on, which adds the class back.
You should skip the current element in the loop.
[...li.parentElement.children].forEach(sib => {
if (sib != li) {
sib.classList.remove('active'))
}
});

I want to change certain names in my UL using a button

I want to change 9 of the names in the UL to a red font using a on click button, while the other 3 names remain in a black font. And I want a button to reset the red fonts back to their original font. Can anyone help?
var title = document.getElementById("title");
var buttons = document.getElementsByClassName("btn");
var buttons = document.getElementsByClassName("btn2");
for (var btnIndex = 0; btnIndex < buttons.length; btnIndex++) {
buttons[btnIndex].onclick = function() {
title.style.color = this.getAttribute('data-color');
}
} else {
title1.style.color = this.getAttribute('data-color');
}
<ul>
<li id="title">John</li>
<li id="title">Jack</li>
<li id="title">Joe</li>
<li id="title1">Jim</li>
<li id="title">David</li>
<li id="title">Sam</li>
<li id="title1">Jay</li>
<li id="title">Frank</li>
<li id="title">Tim</li>
<li id="title">Zack</li>
<li id="title">Lewis</li>
<li id="title1">Danny</li>
<button class="btn" data-color="red">Change 9 names to red</button>
<button class="btn2" data-color="black">Reset</button>
</ul>
There are a couple of problems with your markup, which I'll address below, but to answer your actual question, you can do something like this:
// get references to the buttons
const button1 = document.querySelector('.btn');
const button2 = document.querySelector('.btn2');
// declare a function that adds the class 'red' to items matching the given selector
const select = selector => {
[...document.querySelectorAll(selector)].forEach(
element => element.classList.add('red')
);
}
// declare a function that removes the given class from all elements that currently have it
const deselect = className => {
[...document.querySelectorAll('.' + className)].forEach(
element => element.classList.remove(className)
);
}
// add a click handler to the button that invokes the
// select function above for items whose class includes 'title'
button1.addEventListener('click', () => select('.title'));
// add a click handler to the second button that removes the 'red' class from all items
button2.addEventListener('click', () => deselect('red'));
.red {
color: red;
}
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button class="btn" data-color="red">Change 9 names to red</button>
<button class="btn2" data-color="black">Reset</button>
a more efficient solution
This may not suit your needs, but if you just want to change the color of title items you could toggle a class on the <ul> and apply a css rule:
// get references to the button and ul
const button = document.querySelector('.btn');
const ul = document.querySelector('ul');
// toggle a class on the ul
button.addEventListener('click', () => ul.classList.toggle('red'));
/*
color 'title' items when the
ul has the 'red' class
*/
ul.red .title {
color: red;
}
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button class="btn">Toggle 'title' items to red</button>
markup issues
id attributes must be unique within a document. if you need to attach the same identifier to multiple elements use class instead.
<button> cannot be a child of <ul>.
First, id values must be unique, so you should be using class to
organize the similar <li> elements and use id to uniquely
identify the two buttons.
Also, the only elements that can be a child of a <ul> are <li>,
<script> and <template> elements, not <button>, so the buttons
have to be moved out of the ul.
From there, it's just a matter of setting the two buttons click handlers to the same event handler that loops over the li elements with the given class (not the buttons as you are trying to do) and adds or removes a pre-made class to the list depending on which button was clicked.
// test.js contents
document.getElementById("btn").addEventListener("click", changeColor);
document.getElementById("btn2").addEventListener("click", changeColor);
let items = document.querySelectorAll(".title");
function changeColor(event){
items.forEach(function(item){
// Figure out which button got us here
if(event.target.id === "btn"){
item.classList.add("red"); // Add red
} else {
item.classList.remove("red"); // Remove red
}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Change the Certain Font Color with JavaScript</title>
<style>
.red {color:red;}
</style>
</head>
<body>
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button id="btn">Change 9 names to red</button>
<button id="btn2">Reset</button>
<script src="test.js"></script>
</body>
</html>
Additional notes:
You'll want to stay away from using .getElementsByClassName().
Rather than looping with counter indexes, it's much simpler to use
the Array.forEach() method on the collection returned from .querySelectorAll().
You should avoid using inline styles whenever possible as they are the hardest to override and to maintain. Instead, add, remove, or toggle the use of CSS classes with the .classList API, which is much simpler to use.

Disable dropdown item with CSS or Javascript

I need to disable, deactivate or at least hide a dropdown item called Private request and I can only use CSS or Javascript to do so.
When I inspect the dropdown item it has the class a.js-dropdown-list. But every item in my dropdown has this class. So I can't just use {display: none;} because it will hide all options. Is there no more specific ID for every item in the drop down or can I deactivate items with Javascript?
Drop Down looks like this:
Here the code (1st block is for the picker field, 2nd for the drop-down menue):
<div id="js-organization-picker">
<sd-select class="js-share-with-organisation-picker is-private" data-type="link" data-id="customfield_10203" data-value="38" data-options="[{"label":"Private request","styleClass":"is-private","icon":"locked"},{"label":"Share with Testorganisation","value":38,"icon":"unlocked"}]" resolved="">
<a id="js-customfield_10203-dropdown-trigger" class="aui-dropdown2-trigger aui-button aui-button-link js-trigger customfield_10203-trigger select-dropdown-trigger aui-alignment-target aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left active aui-dropdown2-active aui-alignment-enabled" aria-controls="customfield_10203-dropdown" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger="" data-dropdown2-hide-location="js-customfield_10203-dropdown-container" resolved="" aria-expanded="true" href="#customfield_10203-dropdown">
<span class="aui-icon aui-icon-small aui-iconfont-locked">
: : before
</span> Private request
: : after
</a>
<input name="customfield_10203" type="hidden" class="js-input" value="">
<div id="js-customfield_10203-dropdown-container" class="hidden"></div>
</sd-select>
</div>
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled" role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" style="z-index: 3000; top: 0px; left: 0px; position: absolute; transform: translateX(602px) translateY(918px) translateZ(0px);" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
E.g. you could give the dropdown item ids to identify them. In HTML this would look like this: <p id="yourIdHere"></p>
You can access this item through Javascript using the document.getElementById() function like this: document.getElementById('yourIdHere').style.display = 'none';
If you can't edit the existing html code, youi have to get the element by it's name/value. This is a bit difficult. You have to iterate through all elements of that type and evaluate each name/value. If you have found the one, you was looking for, you can edit/hide it. You would do so (untested):
var elements = document.getElementsByTagName('div'); //div will be the name of the tag of your elements in the dropdown list
var length = elements.length;
for (var i=0, item; item = elements[i]; i++) {
if(item.value == "Private request") { //"Private request" is the name of the element we are looking for
item.style.display = 'none'; //Hide the element
}
}
You could loot trough all 'js-dropdown-items', check its innerText for 'Private request' and set its parentNodes display-property to 'none':
var list = document.getElementsByClassName('js-dropdown-item');
for(var i = 0; i < list.length; i++){
if(list[i].innerText === 'Private request') list[i].parentNode.style.display = 'none';
}
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
VannillaJS Solution document.querySelectorAll(".aui-list > li")[0].style.display = "none";
Welcome!
If I get you right there are plenty of elements with the same ID js-dropdown-list and you want to hide a specific one and there is no additional class for the element and you're not allowed to add specificity to it, let's say by adding of an additional class, you can do the following:
Grab all elements with this id by:
let elements = document.querySelectorAll('.js-dropdown-list'); // this is an array of these elements
let elementToHide = elements[n] // whene n is the number of that element
//hiding the element
elementToHide.style.display = 'none';
Hope that helps!
NOTE: I believe you will have to actually hide it OR use whatever you are using for this pseudo drop down (there was no reference in the question) to manage the disabled state if it provides that. Reference: https://www.w3.org/TR/2014/REC-html5-20141028/disabled-elements.html
Get the element by its text and then hide it. Might need the parent but this directly answers the question. Note this could all be wrapped in a function and then called from where you wish.
function HideByText(elId, findText) {
let group = document.getElementById(elId).getElementsByClassName('js-dropdown-item');
let found = Array.prototype.filter.call(group, function(el) {
return el.innerText === findText;
});
found.forEach(function(el) {
el.style.display = 'none';
});
return found;// in case you need the elements ref.
}
let foundFiltered = HideByText('customfield_10203-dropdown', 'Private request');
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled"
role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
Alternate for parent would be:
Change el.style.display = 'none'; to
if (node.parentElement) {
el.parentElement.style.display = 'none';
}
Have you tried using CSS? Not an ideal solution, but it might be better than using JS for this.
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child {
display: none;
}
If you need to hide the first 2 elements, you could do something like:
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child,
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child + li {
display: none;
}

Target element by attr then append class jQuery

I have a li tag that looks like :
<li class="item maybe" data-selected="1"></li>
<li class="item confused" data-selected="2"></li>
<li class="item why" data-selected="3"></li>
I then have three other elements that look like :
<li class="display"></li>
<li class="display"></li>
<li class="display"></li>
I'm trying to on select of one of the elements append the class to my 2nd list of elements.
So if I selected the li tag with data-selector="1" then my first li tag in my display list will have the class maybe added.
This is what i've tried so far, but i'm getting undefined when I console log my var out :
if ($('.item').attr('data-selected') == 1) {
var itemClassAdd = $('.item').find("[data-selected='1']").attr('class');
console.log(itemClassAdd);
$(".display").addClass(itemClassAdd);
}
Thanks!
I perform action in a click event for convenience:
$("li.item").click(function(){
var index = $(this).data("selected");
$("li.display").eq(index - 1).addClass($(this).attr("class"));
});
If you don't need class item:
$("li.item").click(function(){
var index = $(this).data("selected");
var c = $(this).attr("class").replace("item ", "");
$("li.display").eq(index - 1).addClass(c);
});
The class and the attribute are on the same element, so you use a compound selector, not find:
var itemClassAdd = $('.item[data-selected="1"]').attr('class');
But note that
if ($('.item').attr('data-selected') == 1) {
will only branch of the first element matching .item has data-selected="1", which may or may not be what you want.
Live Example:
if ($('.item').attr('data-selected') == 1) {
var itemClassAdd = $('.item[data-selected="1"]').attr('class');
$(".display").addClass(itemClassAdd);
}
.maybe {
color: green;
}
<ul>
<li class="item maybe" data-selected="1">maybe</li>
<li class="item confused" data-selected="2">confused</li>
<li class="item why" data-selected="3">why</li>
</ul>
<ul>
<li class="display">d1</li>
<li class="display">d2</li>
<li class="display">d3</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

JS hiding a div while targeting anchor

I have multiple divs (class="profile") wich are hidden by default. Each div is only shown when targeted. I want all divs with class="employeeul" to be hidden when one of the profile divs is targeted. I don't get this working with css, does anyone know why? A JS solution is good as well. (I think I can't use something like onclick, because the divs must hide when the anchors are accessed from other sites.)
This is my code (I removed the divs content):
<div class="narrow_content">
<div class="profile" id="m_empfang0"></div>
<div class="profile" id="m_empfang1"></div>
<div class="profile" id="m_mitarbeiter0"></div>
<div class="profile" id="m_mitarbeiter1"></div>
<div class="profile" id="m_mitarbeiter2"></div>
<div class="profile" id="m_mitarbeiter3"></div>
<div class="profile" id="m_mieter0"></div>
<div class="profile" id="m_mieter1"></div>
<div class="profile" id="m_mieter2"></div>
<div class="employeeul">
<ul> <!-- Empfang -->
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
<div class="employeeul">
<ul> <!-- Mitarbeiter -->
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
<div class="employeeul">
<ul> <!-- Mieter -->
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
</div>
It seems like you just need the syntax for displaying/hiding items dynamically when the page has a specific url. In that case, here is a simple JS solution:
//get an array of elements with the class we're interested in working with
var employeeuls = document.getElementsByClassName("employeeul");
//get the current url
var url = window.location.href;
//if the current url is equal to example.php#profile, hide some elements
if(url == "example.php#profile")
{
//iterate over the array and apply the style to hide the elements
for(i=0; i < employeeuls.length; i++)
{
employeeuls[i].style.display = "none";
}
}
//otherwise, the elements should be hidden
else
{
//iterate over the array and apply the style to hide the elements
for(i=0; i < employeeuls.length; i++)
{
employeeuls[i].style.display = "block";
}
}
NOTE: "block" is the default display property for unordered lists.
I understand you're not using jQuery, but I'm going to include the jQuery equivalent for anyone viewing this post in the future:
//variable assigned to all elements with class "employeeul"
var employeeuls = $(".employeeul");
//get the current url
var url = $(location).attr("href");
//apply the style change
if(url == example.php#profile)
{
employeeuls.hide();
}
else employeeuls.show();
If by targeting, you mean the hash value in the URL, you just need to write some JS to grab that hash value and toggle the css. Then toggle show/hide (or a visibility class via jQuery).
$(document).ready(function(){
var $profiles = $('.profile'); // Store all the profiles in a query
var hashTarget = location.hash.replace('#', ''); // Returns hash value
function showTargetedDiv(){
$profiles.hide(); // Hide any divs that may previously be showing
$('#' + hashTarget).show();
}
showTargetedDiv();
$(window).on('hashchange', showTargetedDiv); // Event handler
});

Categories