Changing class of button and display of div with JavaScript - javascript

I have JavaScript to show/hide div on click. Inside that div are more buttons to show/hide PNGs.
I want the clicked button to have a bottom border line until another button in that div is clicked.
I have achieved this but each time I click on a button in the shown div the bottom border line stays on the button when I click the next button.
I've spent hours trying to fix this. please help
let wildCard = document.querySelectorAll(".element-select-container button");
for (let button of wildCard) {
button.addEventListener('click', (e) => {
const et = e.target;
const active = document.querySelector(".active");
let redline = (".redline");
if (active) {
active.classList.remove("redline");
active.classList.remove("active");
}
et.classList.add("active");
et.classList.add("redline");
let allContent = document.querySelectorAll('.button-wrapper');
for (let content of allContent) {
if(content.getAttribute('data-e') === button.getAttribute('data-e')) {
content.style.display = "block";
}
else {
content.style.display = "none";
}
}
});
}
HTML
<div class="element-select-container">
<button id="but81" class="but81 redline" data-e="81" type="button" name="">Doors</button>
<button id="but82" class="but82" data-e="82" type="button" name="">Windows</button>
<button id="but83" class="but83" data-e="83" type="button" name="">Facia</button>
<button id="but84" class="but84" data-e="84" type="button" name="">Guttering</button>
<button id="but85" class="but85" data-e="85" type="button" name="">Garage</button>
<button id="but86" class="but86" data-e="86" type="button" name="">Steps</button>
</div>
CSS
.redline {
border-bottom: 2px solid red;
}

The issue is, on first load, the first button is redline but not active - so, when you press a different button, the code to remove redline from active doesn't find active so redline isn't removed
simple fix
const active = document.querySelector(".active,.redline");
As follows
let wildCard = document.querySelectorAll(".element-select-container button");
for (let button of wildCard) {
button.addEventListener('click', (e) => {
const et = e.target;
const active = document.querySelector(".active,.redline");
if (active) {
active.classList.remove("redline");
active.classList.remove("active");
}
et.classList.add("active");
et.classList.add("redline");
let allContent = document.querySelectorAll('.button-wrapper');
for (let content of allContent) {
if(content.getAttribute('data-e') === button.getAttribute('data-e')) {
content.style.display = "block";
}
else {
content.style.display = "none";
}
}
});
}
.redline {
border-bottom: 2px solid red;
}
<div class="element-select-container">
<button id="but81" class="but81 redline" data-e="81" type="button" name="">Doors</button>
<button id="but82" class="but82" data-e="82" type="button" name="">Windows</button>
<button id="but83" class="but83" data-e="83" type="button" name="">Facia</button>
<button id="but84" class="but84" data-e="84" type="button" name="">Guttering</button>
<button id="but85" class="but85" data-e="85" type="button" name="">Garage</button>
<button id="but86" class="but86" data-e="86" type="button" name="">Steps</button>
</div>

Related

Why does toggling visibility works only after second click?

I have a button that should toggle between visibility visible and hidden, and even though I specify in CSS that the div has visibility: hidden, the JS code first sees the CSS as blank (as if I did not specify the style).
Only after the second click (mouseup event in my case), it detects the visibility and the toggling starts working, why?
Here's a snippet:
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
if (div.style.visibility === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden";
}
}
#div {
visibility: hidden;
}
<button id="button"> toggle </button>
<div id="div">
<h1> Hello, World! </h1>
</div>
div.style reads from the style attribute not the actual applied styles. To fix this you can either use inline styling or get the computed style via getComputedStyle().
Example inline styling:
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
if (div.style.visibility === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden";
}
}
<button id="button"> toggle </button>
<div id="div" style="visibility: hidden;">
<h1> Hello, World! </h1>
</div>
Example getComputedStyle():
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
const style = window.getComputedStyle(div);
if (style.visibility === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden";
}
}
#div {
visibility: hidden;
}
<button id="button"> toggle </button>
<div id="div">
<h1> Hello, World! </h1>
</div>
EDIT: As pointed out in the comments toggling a class is another alternative. This is especially useful if you need to change more then one style.
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
div.classList.toggle('show');
}
#div {
visibility: hidden;
}
#div.show {
visibility: visible;
}
<button id="button"> toggle </button>
<div id="div">
<h1> Hello, World! </h1>
</div>
To evaluate style properties of an element, you need to use the window.getComputedStyle() method.
In your case, the code should be:
<!DOCTYPE html>
<html>
<style>
#div {
visibility: hidden;
}
</style>
<body>
<button id="button"> toggle </button>
<div id="div">
<h1> Hello, World! </h1>
</div>
<script>
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
 if(window.getComputedStyle(div).visibility === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden";
}
}
</script>
</body>
</html>
Soi if you don't want to use inline-css;
let button = document.querySelector("#button");
button.addEventListener("mouseup", toggleVisibility)
function toggleVisibility() {
let div = document.getElementById("div");
let compStylesStatus = window.getComputedStyle(div).getPropertyValue('visibility');
if (compStylesStatus === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden"
}
}
#div {
visibility: hidden;
}
<button id="button"> toggle </button>
<div id="div">
<h1> Hello, World! </h1>
</div>

button toggle display show hide

I want to show-hide the display of these layers with a button click. I can't figure out how to do it with 2 buttons, and 2 divs...
Html:
<div id="first">This is the FIRST div</div>
<div id="second">This is the SECOND div</div>
<button id="toggle">Show first div and hide second div</button>
<button id="toggletoo">Show second div and hide first div</button>
Css:
#first {
display: none;
}
#second {
display: none;
}
Js:
const targetDiv = document.getElementById("first");
const btn = document.getElementById("toggle");
btn.onclick = function () {
if (targetDiv.style.display !== "none") {
targetDiv.style.display = "block";
} else {
targetDiv.style.display = "none";
}
}
https://codepen.io/MaaikeNij/pen/YzrgbQw
Try with the following code:
#first{
display: block; /* <--- change */
}
#second {
display: none;
}
const firstDiv = document.getElementById("first");
const secondDiv = document.getElementById("second");
document.getElementById("toggle").onclick = function () {
if (firstDiv.style.display === "none") {
firstDiv.style.display = "block";
secondDiv.style.display = "none";
} else {
firstDiv.style.display = "none";
secondDiv.style.display = "block";
}
}
There's lots of ways to do this. One common way I've seen in various templates is to add and remove classes. Another way is to call the function from the button's onclick attribute. But my favorite is to write a function that requires no editing of the div HTML because I don't want to interfere with the HTML guy's work, I just want to put functioning code in there. (BTW, I am positive there is a more elegant way to write this, but here ya go!)
const firstDiv = document.querySelector("#first");
const secondDiv = document.querySelector("#second");
const firstButt = document.querySelector("#toggle");
const secondButt = document.querySelector("#toggletoo");
firstButt.addEventListener("click",toggleDivShowHide);
secondButt.addEventListener("click",toggleDivShowHide);
function toggleDivShowHide() {
if (firstDiv.style.display !== "none") {
firstDiv.style.display = "none";
secondDiv.style.display = "block";
} else {
firstDiv.style.display = "block";
secondDiv.style.display = "none";
}
}
You're saying "if the first div is set to none, then set it to block and set the second div to none. Otherwise, do the opposite."
I tried something different, this is working :)))
<div id="first" style="display:none;"> This is the FIRST div</div>
<div id="second" style="display:none;"> This is the SECONDdiv</div>
<input type="button" name="answer" value="Show first div and hide second div" onclick="showDivOne()" />
<input type="button" name="answer" value="Show second div and hide first div" onclick="showDivTwo()" />
function showDivOne() {
document.getElementById('first').style.display = "block";
document.getElementById('second').style.display = "none";
}
function showDivTwo() {
document.getElementById('second').style.display = "block";
document.getElementById('first').style.display = "none";
}
https://codepen.io/MaaikeNij/pen/vYeMGyN
Correction: you should add event Listener for both toggle & toggletoo.
Solution: solution with reusable code.
const Toggles = document.querySelectorAll('.toggle');
const Hides = document.querySelectorAll('.hide');
Toggles.forEach((el) => {
el.addEventListener("click", (e) => {
Hides.forEach((el) => {
el.parentElement.firstElementChild.classList.add('hide');
});
e.target.parentElement.firstElementChild.classList.toggle('hide');
});
})
.hide {
display: none;
}
<div>
<div class="hide">This is the FIRST div</div>
<button class="toggle">Show first div and hide first div</button>
</div>
<div>
<div class="hide">This is the SECOND div</div>
<button class="toggle">Show second div and hide first div</button>
</div>
<div>
<div class="hide">This is the Third div</div>
<button class="toggle">Show Third div and hide first div</button>
</div>
<div>
<div class="hide">This is the Fourth div</div>
<button class="toggle">Show Fourth div and hide first div</button>
</div>
For precisely such cases, javascript has the toggle function. I rewrite your code a little bit.
const btns = document.querySelectorAll(".toggleBtn");
btns.forEach(b => {
b.onclick = function (e) {
reset();
console.log(e.target.getAttribute('data-target'))
const target = e.target.getAttribute('data-target');
const t = document.querySelector('#' + target);
t.classList.toggle('hide');
}
});
function reset() {
const divs = document.querySelectorAll('.out');
divs.forEach(d => d.classList.add('hide'))
}
.hide {
display: none;
}
<div id="first" class="out hide">This is the FIRST div</div>
<div id="second" class="out hide">This is the SECOND div</div>
<button class="toggleBtn" data-target="first">Show first div and hide second div</button>
<button class="toggleBtn" data-target="second">Show second div and hide first div</button>

I want to make a stepper component

I want to hide prev btn and the other words
But I want to show them and prev btn one by one when I press next button and display finish btn i am on the latest word.
The buttons, prev, next and finish do the things which are not the same when I have finish button I want to post the words.
I tried many time but not worked. Here is my code that I've tried:
function nextBtn() {
var itemOne = document.getElementById("step-1");
var itemTwo = document.getElementById("step-2");
var itemThree = document.getElementById("step-3");
var itemFour = document.getElementById("step-4");
var prevBtn = document.getElementById("prevBtn");
var nextBtn = document.getElementById("nextBtn");
if (itemOne.style.display == "block" && itemTwo.style.display == "none" && prevBtn.style.display == "none") {
itemOne.style.display = "none";
itemTwo.style.display = "block";
prevBtn.style.display = "block";
}
else {
console.log('Xatolik ishlamayapti');
}
}
#step-1 {
display: block;
}
#step-2 {
display: none;
}
#step-3 {
display: none;
}
#step-4 {
display: none;
}
#prevBtn {
display: none;
}
#nextBtn {
display: block;
}
<div class="step-container">
<div id="step-1">Hello</div>
<div id="step-2">Hi</div>
<div id="step-3">Salom</div>
<div id="step-4">Molas</div>
<button id="prevBtn" #click="prevBtn()">back</button>
<button id="nextBtn" #click="nextBtn()">next</button>
</div>
What's wrong at above link.
Thank you in advance.
The main problem with your approach is that itemOne.style.display == "block" will not evaluate to true because it doesn't consider that the node has some css set externally.
It would make more sense to use html classes for your step divs so that you can select them all at once with querySelectorAll().
The logic would be easier to manage if you use a variable to track which number step is the current step.
Then you can just increase and decrease the variable each time you click on either the previous or next buttons.
const allSteps = document.querySelectorAll('.step')
const totalSteps = allSteps.length
const prevButton = document.querySelector('#prevBtn')
const nextButton = document.querySelector('#nextBtn')
const finishButton = document.querySelector('#finishBtn')
// Hide everything except for #step-1
document
.querySelectorAll(".step:not(#step-1)")
.forEach(step => (step.style.display = "none"))
// Hide the prev button
prevButton.style.display = 'none'
// Hide the finish button
finishButton.style.display = 'none'
let currentStep = 1
function nextBtn() {
currentStep++;
refreshDisplay()
}
function prevBtn() {
currentStep--;
refreshDisplay()
}
function refreshDisplay() {
// hide every step
allSteps.forEach(step => (step.style.display = "none"))
// show only the currentStep
document.querySelector(`#step-${currentStep}`).style.display = 'block'
// hide or show the prevButton
if (currentStep === 1) {
prevButton.style.display = 'none'
} else {
prevButton.style.display = 'inline-block'
}
// hide or show nextButton & finish button
if (currentStep === totalSteps) {
nextButton.style.display = 'none'
finishButton.style.display = 'inline-block'
} else {
nextButton.style.display = 'inline-block'
finishButton.style.display = 'none'
}
}
function finish() {
console.log('you are finished')
}
<div class="step-container">
<div class="step" id="step-1">Hello</div>
<div class="step" id="step-2">Hi</div>
<div class="step" id="step-3">Salom</div>
<div class="step" id="step-4">Molas</div>
<button id="prevBtn" onclick="prevBtn()">back</button>
<button id="nextBtn" onclick="nextBtn()">next</button>
<button id="finishBtn" onclick="finish()">finish</button>
</div>
Something like this?
var activeButton = 0;
function next() {
document.getElementById(activeButton).classList.remove('active');
activeButton++;
document.getElementById(activeButton).classList.add('active');
}
function previous() {
document.getElementById(activeButton).classList.remove('active');
activeButton--;
document.getElementById(activeButton).classList.add('active');
}
.step {
display: none;
}
.active {
display: inline;
}
<button id="0" class="active step">First</button>
<button id="1" class="step">Second</button>
<button id="2" class="step">Third</button>
<button id="3" class="step">Fourth</button>
<button id="4" class="step">Fifth</button>
<button id="5" class="step">Sixth</button>
<button id="6" class="step">Seventh</button>
<hr>
<button id="next" onclick="next()">Next</button>
<button id="next" onclick="previous()">Previous</button>

Changing color of only button that was clicked

I mean I want to change CSS properties of only the button that I've clicked and at the same time set other buttons to previous color. Hope I explained my problem clear
for(let i = 0; i < categoryBtns.length; i++) {
categoryBtns[i].addEventListener('click', function() {
let attr = this.getAttribute('id');
if(categoryBtns[i - 1].id != attr || categoryBtns[i + 1].id != attr) {
log([i]);
console.log('works');
this.style.backgroundColor = '#000000';
} else {
log('no');
}
})
}
I have also code that shows only divs that have current category. Should I code buttons in the same time when divs are showing and hiding?
$(document).ready(function() {
$('.category-item').click(function() {
let category = $(this).attr('id');
if(category == 'all') {
$('.prod_item').addClass('hide');
setTimeout(function() {
$('.prod_item').removeClass('hide');
}, 300);
} else {
$('.prod_item').addClass('hide');
setTimeout(function() {
$('.' + category).removeClass('hide');
}, 300);
}
});
});
I hope that I understood what you want correctly
const btns = document.querySelectorAll('.btn')
btns.forEach(btn => {
btn.addEventListener('click', () => {
btns.forEach(b => {
(b.classList.contains("active"))?
b.classList.remove("active"):true
});
btn.classList.add("active")
});
})
.active {
background-color: blue;
}
<button class = "btn">Click Me</button>
<button class = "btn">Click Me</button>
<button class = "btn active">Click Me</button>
<button class = "btn">Click Me</button>
<button class = "btn">Click Me</button>
use Array.forEach() to loop through the buttons and add/remove a styled class:
const btns = document.querySelector(".buttons");
const arr = Array.prototype.slice.call(btns.children, 0);
arr.forEach((el) => {
el.addEventListener("click", () => {
arr.forEach((el2) => {
el2.classList -= "active";
});
el.classList.toggle("active");
});
});
button.active {
color: red;
}
<div class="buttons">
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
<button>Button 4</button>
<button>Button 5</button>
</div>
You can add a class for the button clicked state, and a default color for all buttons inside divs with class category-item. One javascript function removes the clicked class from all buttons while the other adds it to a specific button.
$(document).ready(function() {
$('.category-item input[type="button"]').click(function() {
removeClickedClass();
addClickedClass(this.id);
});
function removeClickedClass() {
$('.category-item input[type="button"]').removeClass("btnColorClicked");
}
function addClickedClass(elemID) {
let id = "#" + elemID;
$(id).addClass("btnColorClicked");
}
});
.category-item input[type="button"] {
font-weight: bold;
background-color: #4CAF50;
cursor: pointer;
}
.btnColorClicked {
background-color: #0099ff !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="category-item">
<input type="button" class="" id="1" value="hi" />
</div>
<div class="category-item">
<input type="button" class="" id="2" value="there" />
</div>
<div class="category-item">
<input type="button" class="" id="3" value="hey" />
</div>
Here is an answer for your first block without jQuery, but you should get it.
function colorizeButtons(id) {
for (let i = 0; i < categoryBtns.length; i += 1) {
const buttonId = categoryBtns[i].getAttribute('id');
// Clicked button
if (buttonId === id) {
// Set the clicked color button
} else {
// Set other buttons color
}
}
}
for (let i = 0; i < categoryBtns.length; i++) {
categoryBtns[i].addEventListener('click', function() {
let attr = this.getAttribute('id');
colorizeButtons(attr)
});
}
here is an example with jquery btns are the list of buttons elements and when clicked they turn red if click again they turn white
$(btns).on("click",function(){
if(!this.clicked){
this.clicked = true;
$(this).css("background-color", "red");
}
else{
this.clicked = false;
$(this).css("background-color", "white");
}
});

How to dynamically render HTML

Recently I came across a question, here it goes, I have two buttons BTN1, BTN2. On click of BTN1 it should disappear and two new BTN_A and BTN_B has to appear, on click or BTN_A, it should disappear & BTN1.A, BTN1.B should appear. How to achieve this if I still want to click on BTN's and make them disappear.
I thought we can make "display: none" but for how many, how to render a html dynamically in the best way?
There are 4 possibilities to hide a DOM element like a button.
The first three are css style changes:
opacity: 0;
visibility: hidden;
display: none;
removing the element from the DOM with removeChild()
The needed code is the following:
document.getElementById('myBtn').style.opacity = '0';
document.getElementById('myBtn').style.display = "none";
document.getElementById('myBtn').style.visibility = "hidden";
The code for adding and removing elements goes like this:
var div = document.getElementById('endlessBtnContainer');
div.innerHTML = div.innerHTML + '<button id="addBtn" onclick="addBtn()">addBtn</button>';
and removing
var div = document.getElementById('addBtn');
div.parentNode.removeChild(div);
opacity: 0; will simply make the element not visible, but it is still existing normally. So you can still click the button.
visibility: hidden; Will hide the element, but it will still take
up the same space it had when it was still visible. It won't be
clickable anymore.
display: none; Will hide the element and it won't take any space
anymore. Therefore following HTML elements will flow into the new
available space.
#btnA, #btnB, #btn1A, #btn1B{
opacity: 0;
}
<script>
function hideElem()
{
for (var i = 0; i < arguments.length; i++) {
//document.getElementById(''+arguments[i]).style.opacity = '0';//just invisible, still clickable
//document.getElementById(''+arguments[i]).style.display = "none";//no space taken
document.getElementById(''+arguments[i]).style.visibility = "hidden";//invisible, not clickable
}
}
function showElem(targetElem)
{
for (var i = 0; i < arguments.length; i++) {
document.getElementById(''+arguments[i]).style.opacity = '1';
}
}
function addBtn()
{
var div = document.getElementById('endlessBtnContainer');
div.innerHTML = div.innerHTML + '<button id="addBtn" onclick="addBtn()">addBtn</button>';
}
function removeBtn()
{
var div = document.getElementById('addBtn');
div.parentNode.removeChild(div);
}
</script>
<button id="btn1" onclick="hideElem('btn1', 'btn2'); showElem('btnA', 'btnB');">
btn1
</button>
<button id="btn2">
btn2
</button>
<button id="btnA" onclick="hideElem('btnA', 'btnB'); showElem('btn1A', 'btn1B');">
btnA
</button>
<button id="btnB">
btnB
</button>
<button id="btn1A">
btn1A
</button>
<button id="btn1B">
btn1B
</button>
<button id="addBtn" onclick="addBtn()">
addBtn
</button>
<button id="removeBtn" onclick="removeBtn()">
removeBtn
</button>
<div id="endlessBtnContainer">
</div>

Categories