Looking to remove a class if a certain button is clicked.
<div class="slide-container">
<section class="about" id="slide-0">
<div class="menu-total">
<nav class="nav">
<button class="nav_link home" onclick="slideTo('slide-2')">HOME</button>
<button class="nav_link about" onclick="slideTo('slide-0')">ABOUT</button>
<button class="nav_link fun-stuff" onclick="slideTo('slide-1')">FUN STUFF</button>
<button class="nav_link professional" onclick="slideTo('slide-3')">PROFESSIONAL</button>
<button class="nav_link contact" onclick="slideTo('slide-4')">CONTACT</button>
</nav>
<div class="hamburger">
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
<span class="hamburger__patty"></span>
</div>
</div>
The one I want to remove the class on is the HOME button. So "slideTo('slide-2)". If it's clicked on the others then the class is kept. I believe someone is either wrong with my loop or not getting the ID correctly of the items/
function slideTo(slideId) {
const slide = document.getElementById(slideId);
slide.scrollIntoView({
behavior: 'smooth'
})
// above this line works fine
let nonHome = document.querySelectorAll('.slide-container section');
let nonHomeID = document.getElementById('slide-2');
var i;
setTimeout(function(){
for (i=0; i < nonHome.length; i++ ){
// i believe it's somewhere here it is wrong
if (nonHome[i].id != nonHomeID){
nonHome[i].classList.add("nav-visibility");
} else{
nonHomeID.classList.remove("nav-visibility");
}
}
}, 1000)
}
If you can use jquery library, you can write in the HTML:
<button class="nav_link" data-value="home">HOME</button>
...
and then in the JS code:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // Get the data-value clicked
$(".nav_link").each(function() { // Loop through all elements of the class 'nav-link'
var v = $(this).data("value");
if (v == valueClicked) {
$(this).removeClass("nav-visibility");
} else {
$(this).addClass("nav-visibility");
}
)
}
Not much simpler, but the HTML is cleaner.
Simpler version if it is not required to browse through all buttons at each button click:
$(".nav_link").on("click", function() {
var valueClicked = $(this).data("value"); // The value of the button clicked by the user
if (valueClicked == "home") {
$(this).removeClass("nav-visibility");
console.log('remove')
} else { $(this).addClass("nav-visibility");
console.log('add')
}
});
Related
So I'm trying to create a chat application like messenger.
When I press the button, a new conversation should be started. I want to add a list item in my overview bar on the left but there can only be one selected, and that one has the 'history-item-selected' classname. So every new convo gets that classname, while the others ones get another classname to change it's appearance but it won't work.
const newConvoButton = document.getElementById("newmessage");
const addNewConvo = (e) => {
e.preventDefault();
const myMessages = document.getElementById('history');
let newListItem = document.createElement('li');
newListItem.textContent = "user " + Math.floor(Math.random(2 - 100) * 100);
myMessages.appendChild(newListItem);
if (newListItem.classList = 'history-item-selected') {
newListItem.classList.add('history-item-selected');
} else {
newListItem.classList.add('history-item')
};
};
newConvoButton.addEventListener('click', addNewConvo);
<main>
<div id="top">
<span>
<h2>My conversations</h2>
</span>
<button type="submit" id="newmessage">+</button>
</div>
<div id="messagecontainer">
<ul id="history"></ul>
<id id="chatscreen">
<ul id="messages">
<li>yolo</li>
</ul>
<div id="messagebottom">
<input type="text" placeholder="Start met typen" size="28" height="auto"> <button type="submit">Send</button>
</div>
</id>
</div>
</main>
There is a "tautological" way to do what you are trying to do.
var addNewConvo = (e)=> {
var nodes = document.querySelectorAll(".history-item-selected");
nodes.forEach(function(elem) {
this.classList.remove("history-item-selected");
});
e.target.classList.add("history-item-selected");
}
In your CSS, you should have something like
.history-item {
/*Styles for history-item*/
}
.history-item.history-item-selected {
/*Styles for elements with both */
}
I have a well functioning accordion list that allows me to add new items to the list and they will immediately have the accordion functionality. Although, I would like to have only one accordion item open at a time. All of the answers I've found regarding this have all been for static lists and don't really help with my issue. I apologize if this is a bad question, but I have spent hours on this with no luck and I am out of ideas. Thanks in advance for your help.
HTML: There is more to the HTML. I just added the relevant elements.
<body>
<div class="container">
<!-- New accordion item added here -->
</div>
<script src="main.js"></script>
</body>
Javascript:
// Get items
const addAccBtn = document.getElementById('addAccBtn');
const container = document.querySelector('.container');
addAccBtn.addEventListener('click', e => {
e.preventDefault();
let newAccItem = document.createElement('div');
newAccItem.innerHTML = `
<div class="acc-title">
<i class="fas fa-trash delete"></i>
<h3 class="header-click">${accName}</h3>
<i class="fas fa-sort-down down-arrow"></i>
</div>
<div class="acc-info hidden">
<i class="far fa-edit"></i>
<h4>Section 1</h4>
<p>${input1}</p>
<h4>Section 2</h4>
<p>${input2}</p>
</div>
`;
container.appendChild(newAccItem);
let downBtn = newAccItem.firstElementChild.childNodes[5]; // .down-arrow
let info = newAccItem.firstElementChild.nextElementSibling; // .acc-info
downBtn.addEventListener('click', () => {
if(downBtn.parentElement.nextElementSibling == info && info.classList.contains('hidden')) {
info.classList.remove('hidden');
info.classList.add('active');
}
else {
info.classList.remove('active');
info.classList.add('hidden');
}
});
});
Again, the accordion items will all open and close as they should, i would just like one item open at a time. Thanks again for your time.
I believe these lines should work
...
let downBtn = newAccItem.firstElementChild.childNodes[5]; // .down-arrow
let info = newAccItem.firstElementChild.nextElementSibling; // .acc-info
downBtn.addEventListener('click', () => {
//here you close all opened accordions ---------------
document.querySelectorAll(".acc-info.active").forEach(element => {
if (element !== info) {
element.classList.remove("active");
element.classList.add("hidden");
}
};
// --------------------------------------
if(downBtn.parentElement.nextElementSibling == info && info.classList.contains('hidden')) {
info.classList.remove('hidden');
info.classList.add('active');
}
else {
info.classList.remove('active');
info.classList.add('hidden');
}
});
});
_ edit _
added a if
I have a click event that adds an active class to the link's parentNode. On click the active class should be removed from the siblings of the parentNode. This is the code so far:
categories = document.querySelectorAll('.categories');
for(var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
I tried the line that is commented out, and that breaks the adding of the class on click. Is there an equivalent to jQuery's siblings().removeClass('active')? Thanks for any help.
Here is the DOM for this section:
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
UPDATE - this is the original full code snippet:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
for(var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
}
</script>
</body>
</html>
UPDATE after incorporating BRK's code snippet:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent active">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active');
this.parentNode.classList.add('active');
}
});
</script>
</body>
</html>
Can you try doing like this? It Might help!
categories = document.querySelectorAll('.categories');
for(let i = 0; i < categories.length; i++) {
categories[i].onclick = () => {
// ('.categoriesparent').classList.remove('active');
this.parentNode.classList.add('active');
}
You can first remove the active class from all the siblings of parent (and the parent itself) and then add to the parent
for (var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
[ ...getSiblingsAndMe(this.parentNode) ].forEach( el => el.classList.remove( 'active' ) );
this.parentNode.classList.add('active');
}
}
function getSiblingsAndMe( el )
{
return el.parentNode.children;
}
Demo
categories = document.querySelectorAll('.categories');
for (var i = 0; i < categories.length; i++) {
categories[i].onclick = function(e) {
[ ...getSiblingsAndMe(this.parentNode) ].forEach( el => el.classList.remove( 'active' ) );
this.parentNode.classList.add('active');
}
}
function getSiblingsAndMe( el )
{
return el.parentNode.children;
}
.categoriesparent
{
display:block;
}
.active
{
background-color:pink;
}
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
Inside the onclick handler you can again use document.querySelector('.categoriesparent.active') . This will return the first matched element and then use classList.remove to remove the active class from it.
this.parentNode refers to the element in context
var categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active')
this.parentNode.classList.add('active');
}
})
.active {
color: red;
}
<div id="nav">
<span class="categoriesparent active">
<a class="categories">Link</a>
</span>
<span class="categoriesparent">
<a class="categories">Link2</a>
</span>
</div>
Update from Jamie:
I used your suggestion like so:
<html>
<head></head>
<body>
<div id="nav">
<span class="categoriesparent active">
Link
</span>
<br><br>
<span class="categoriesparent">
Link2
</span>
</div>
<script>
categories = document.querySelectorAll('.categories');
categories.forEach(function(cat, index) {
cat.onclick = function(e) {
document.querySelector('.categoriesparent.active').classList.remove('active');
this.parentNode.classList.add('active');
}
});
</script>
</body>
</html>
I get an "Uncaught TypeError: undefined is not a function" error. Thanks for your input!
I'm trying to make the rest of my chat room app disabled while a modal is open. I've been using element.disable = true to disable the buttons and this has worked. I have a ul where each li is the name of a chat room that is clickable and opens up its respective chat room in another container. I'm trying to disable the lis using the same disable.true method. I'm using a for loop to iterate through the array of lis, but it isn't working.
I used console.log to view the variable with the array stored in it (var lis) as well as the console.log(lis.length). The console shows that the array has a length of 5 but returns lis.length as 0.
Would be much appreciated if someone could tell me what I'm doing incorrectly.
HTML:
<div class"home-template" id="home">
<div class="rooms-container">
<h1 class="app-title">Bloc Chat</h1>
<ul id="rooms-list">
<li class="room-item" id="room-item" ng-repeat="chat in home.chatRooms">
{{ chat.$value }}
</li>
</ul>
<button class="btn btn-warning" id="new-room-button" type="button" ng-click="home.open()">New room</button>
<button class="btn btn-warning" id="delete-cookies-button" type="button" ng-click="home.deleteCookies()">Delete Cookie for testing</button>
</div>
<div class="messages-container">
<h1 class="current-room" ng-bind="home.activeRoom"></h1>
<ul class="messages-list">
<li class="message-bubble" ng-repeat="message in home.messages">
<div class="username">{{ message.username }}</div>
<div class="sentAt">{{ message.sentAt }}</div>
<div class="content">{{ message.content }}</div>
</li>
</ul>
</div>
</div>
JavaScript in a home controller:
home.cookieDisplay = $cookies.get('blocChatCurrentUser');
var modals = document.getElementsByClassName('modal');
var lis = document.getElementsByClassName('room-item');
var newButton = document.getElementById('new-room-button');
var delButton = document.getElementById('delete-cookies-button');
if (modals.length === 0) {
newButton.disabled = false;
delButton.disabled = false;
for (var i = 0; i < lis.length; i++) {
lis[i].disabled.false;
}
} else if (modals.length !== 0) {
newButton.disabled = true;
delButton.disabled = true;
for (var i = 0; i < lis.length; i++) {
// lis[i].setAttribute('display', 'none');
lis[i].disabled.true;
}
}
Here's what my console looks like:
You can't disable the li itself.
You can either disable the anchor tag (a) in it for example like this (refernece):
document.getElementById("tab_c").childNodes[0].onclick = function() {return false;};
Or you can set pointer-events:noneas it has been done using CSS (reference):
.disabled {
pointer-events:none; //This makes it not clickable
opacity:0.6; //This grays it out to look disabled
}
Hi i currently have two toggles, one is on the sidebar and one is in the main body. They currently work together which is annoying, even though i am using to different scripts. The scripts i am using at the moment for the toggles are almost identical, however, even when using completely different scripts they still work together.
what i mean by work together is when i click the toggle on the main body the side bar toggle reacts.
They are toggles which collapse on oclick.
<script>
var divs = ["Menu", "Add"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<script>
$(document).ready(function () {
// set up the click event
$('.body > a').on('click', function(){
$(this).next('div').siblings('div:not(#Menu)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#Menu').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<!-- sidebar toggle-->
<script>
var divs = ["Order", "Rest", "Franc"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<!-- Change color on click-->
<script>
$(document).ready(function() {
$('.sidebar h3').on('click', function() {
$('.sidebar h3').css('color', 'black');
$(this).css('color', 'red');
});
$('h3#open').trigger('click'); //Your account red on page load
});
</script>
<!--Your account toggle open on load -->
<script>
$(document).ready(function () {
// set up the click event
$('.sidebar > a').on('click', function(){
$(this).next('div').siblings('div:not(#Franc)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#francc').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<div class="sidebar">
<!-- Orders toggle-->
<a id="order" class="header" href="#" onclick="toggleVisibility('Order');"><h3 id="orderr">Orders</h3></a>
<div id="Order" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Red">Overview</li>
</ul>
</div>
</div>
<!--Restaurant toggle-->
<a id="restt" class ="header"href="#" onclick="toggleVisibility('Rest');"><h3>Your Restaurants</h3></a>
<div id="Rest" style="display: none;"><div>
<ul class="tabs">
<!-- <li id="order" class="rred">restaurant</li>-->
<li id="order" class="rgreen">New restaurant</li>
</ul>
</div>
</div>
<!-- Account toggle-->
<a id="francc" name="account" class ="header" href="#" onclick="toggleVisibility('Franc');"><h3 id="open">Your Account</h3></a>
<div id="Franc" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Blue" >Order History</li>
</ul>
</div>
</div>
</div>
<div id=body>
<!-- Menu toggle -->
<div class="container_head"> <!-- red header top of container-->
<a id="Menu" class="header" href="#" onclick="toggleVisibility('Menu');"><h3>Menu Section</h3></a>
</div>
<div id="Menu_form" style="display: none;">
<form id="MenuForm" action ="javascript:void(0);" method="POST">
<!-- <div class="field">-->
<label for="Name">Name</label>
<input type="text" name="Name" id="Name" placeholder="Steaks pattern="[a-zA-Z]"
required tabindex="1">
<br>
<label for="Description">Description</label>
<input type="text" name="Description" id="Description" placeholder="Fresh USDA Choice steaks, seasoned with hickory-smoked sea salt." tabindex="2">
<br>
<div class="field">
<input type="submit" value="Save">
</div>
</form>
</div>
<a id="add_prod" class="header" href="#" onclick="toggleVisibility('Add');"><h3>Orders</h3></a>
<div id="add" style="display: none;">
</div>
Bringing together #j08691 and Leo Farmer's comments, you need to have unique IDs and function names. When you call toggleVisibility(...), it's going to call the second declaration of that method. Also, when you call document.getElementById(...) on something like "order", it's going to stop at the first instance it finds (In your case, the a tag).
Give your functions unique names, give your items unique IDs (if you want them to all do the same thing, you can look at using the same class for each item), and you should be in a better spot.