Collapse one at the time on different divs - javascript

const buttons = document.querySelectorAll('.collaps');
const colls = document.querySelectorAll('.collaps_content');
buttons.forEach((thisButton, index) => {
thisButton.addEventListener('click', () => {
colls[index].style.display !== 'none'
? colls[index].style.display = 'none'
: colls[index].style.display = 'block';
});
});
Html
<div class="container-content">
<div class="buttons">
<button class="collaps">Btn1</button>
<button class="collaps">Btn2</button>
<button class="collaps">Btn3</button>
<button class="collaps">Btn4</button>
</div>
<div class="collaps_content" style="display: none;">
Btn1
</div>
<div class="collaps_content" style="display: none;">
Btn2
</div>
<div class="collaps_content" style="display: none;">
Btn3
</div>
<div class="collaps_content" style="display: none;">
Btn4
</div>
</div>
Is working fine, but I only want one collaps_content open at a time, that part is not working.
When I click on every button they are all open and I don't want that to happen.
I tried to look for solutions but so far none worked.

If I understood correctly, you want to close any other open collapsible divs when clicking a button. You can do this by first closing all collapsible divs, and then open the correct one like this:
const buttons = document.querySelectorAll('.collaps');
const colls = document.querySelectorAll('.collaps_content');
buttons.forEach((thisButton, index) => {
thisButton.addEventListener('click', () => {
colls.forEach(b => b.style.display = 'none');
colls[index].style.display !== 'none'
? colls[index].style.display = 'none'
: colls[index].style.display = 'block';
});
});
I just added the colls.forEach(b => b.style.display = 'none'); in your existing JS.

Related

Hide/display div onclick

I have a script which hides an image and displays a text on the click of a button. However, I have similar buttons doing the same action in different divs. When I click the button the first button gets affected, no matter what button is pressed.
How do I manage to fix this?
Underneath is my JS. How do I make it so that the button only affects itself, and not just the first button?
function hideText() {
const btn = document.querySelector('#info');
const infoHide = document.querySelector('.info-hide');
infoHide.style.display = "block"
btn.style.display = 'none'
setTimeout(()=>{btn.style.display = 'block'; infoHide.style.display= "none"}, 2000)
}
<div>
<button id="info" onClick="hideText()"> A button </button>
<div class="info-hide" style="display:none;">Copied!</div>
</div>
<div>
<button id="info" onClick="hideText()"> A button </button>
<div class="info-hide" style="display:none;">Copied!</div>
</div>
I changed your event listener to be aware of the element that triggered the event. Actually that's not strictly an event listener but just a function that gets called when the event occurs.
There are better ways to deal with it using .addEventListener
function hideText(target) {
const infoHide = target.parentElement.querySelector('.info-hide');
infoHide.style.display = "block"
target.style.display = 'none'
setTimeout(() => {
target.style.display = 'block';
infoHide.style.display = "none";
}, 2000)
}
button{
cursor: pointer;
margin-bottom: 1rem;
}
<div>
<button id="info1" onClick="hideText(this);">A button</button>
<div class="info-hide" style="display:none;">Copied!</div>
</div>
<div>
<button id="info2" onClick="hideText(this);">A button</button>
<div class="info-hide" style="display:none;">Copied!</div>
</div>
Anyway as another user pointed out in comments, the id attribute should be unique so I edited the answer to fulfill that condition.
And here I added the approach using a strategy not involving the event listener defined declaratively in the html:
document.addEventListener('DOMContentLoaded',()=>{
document.querySelectorAll('.smartbutton').forEach((btn)=>{
btn.addEventListener('click', (event)=>{ hideText(event.target); });
});
});
function hideText(target) {
const infoHide = target.parentElement.querySelector('.info-hide');
infoHide.style.display = "block"
target.style.display = 'none'
setTimeout(() => {
target.style.display = 'block';
infoHide.style.display = "none";
}, 2000)
}
.smartbutton{
cursor: pointer;
margin-bottom: 1rem;
}
.info-hide{
display: none;
}
<div>
<button id="info1" class="smartbutton">A button</button>
<div class="info-hide">Copied!</div>
</div>
<div>
<button id="info2" class="smartbutton">A button</button>
<div class="info-hide">Copied!</div>
</div>
querySelector pulls the first element that matches your string. Thats why always first button and first info gets affected. You can provide button itself with this keyword and provide an id which determines the div to appear.
function hideText(button, infoClassname) {
const info = document.querySelector(`.${infoClassname}`);
console.log(button)
info.style.display = "block"
button.style.display = 'none'
setTimeout(() => {
button.style.display = 'block';
info.style.display = "none"
}, 2000)
}
<div>
<button id="info" onClick="hideText(this, 'info-hide-1')"> A button </button>
<div class="info-hide-1" style="display:none;">Copied!</div>
</div>
<div>
<button id="info" onClick="hideText(this, 'info-hide-2')"> A button </button>
<div class="info-hide-2" style="display:none;">Copied!</div>
</div>
change your id in div from all 'info' to 'info1'/'info2'/'info3'/, and do same change in your js const btn = document.querySelector('#info1');

How to simplify this code shared in image below?

I want to show div content on button click .and thee is 3 different button following 3 different content. I tried this logic and it made my code lengthy. how to simplify is code using loop or condition?
function replace1(){
document.getElementById("con1").style.visibility="visible";
document.getElementById("con2").style.visibility="hidden";
document.getElementById("con3").style.visibility="hidden";
document.getElementById("con4").style.visibility="hidden";
document.getElementById("con5").style.visibility="hidden";
document.getElementById("con6").style.visibility="hidden";
}
function replace2(){
document.getElementById("con1").style.visibility="hidden";
document.getElementById("con2").style.visibility="visible";
document.getElementById("con3").style.visibility="hidden";
document.getElementById("con4").style.visibility="hidden";
document.getElementById("con5").style.visibility="hidden";
document.getElementById("con6").style.visibility="hidden";
}
function replace3(){
document.getElementById("con1").style.visibility="hidden";
document.getElementById("con2").style.visibility="hidden";
document.getElementById("con3").style.visibility="visible";
document.getElementById("con4").style.visibility="hidden";
document.getElementById("con5").style.visibility="hidden";
document.getElementById("con6").style.visibility="hidden";
}
enter image description here
.active-button {
background: red;
}
<button class="replace-button" onclick="replace(1, this)"></button>
<button class="replace-button" onclick="replace(2, this)"></button>
<button class="replace-button" onclick="replace(3, this)"></button>
function replace(visibleIndex, _this) {
const buttons = document.querySelectorAll('.replace-button');
buttons.forEach(button => button.classList.remove("active-button"));
_this.classList.add("active-button");
for(let i = 1; i < 7; i++) {
let element = document.getElementById("con" + i)
i === visibleIndex ? element.style.visibility = "visible" : element.style.visibility = "hidden";
}
}
Use a class - add class="con" to each element - also use hidden instead of visibility since the hidden divs still will take up space
const toggle = id => cons
.forEach(con => con.hidden = con.id !== id);
Here is a version that will change the colour of the button too.
You will need to use hidden or display:none to have the divs stay in one place
window.addEventListener('DOMContentLoaded', function() {
const cons = document.querySelectorAll('.con');
const buts = document.querySelectorAll('.toggle');
const toggle = id => cons
.forEach(con => con.hidden = con.id !== id);
document.getElementById('nav').addEventListener('click', function(e) {
const tgt = e.target.closest('button');
if (tgt.classList.contains('toggle')) {
toggle(tgt.dataset.id)
buts.forEach(but => but.classList.remove('active'));
tgt.classList.add('active');
}
})
})
.active {
background-color: green;
}
<nav id="nav">
<button type="button" class="toggle" data-id="con1">Con 1</button>
<button type="button" class="toggle" data-id="con2">Con 2</button>
<button type="button" class="toggle" data-id="con3">Con 3</button>
</nav>
<div id="con1" class="con" hidden>
<h1>Con 1</h1>
</div>
<div id="con2" class="con"hidden>
<h1>Con 2</h1>
</div>
<div id="con3" class="con" hidden>
<h1>Con 3</h1>
</div>

window.addEventListener function is not working at all times

Through this code i have to hide the dropdown-container when a user clicked outside of the button. And the code works fine initially. But later, it is not responding to the onclick event on button also. sometimes it closes the dropdown if i cliked a button. I have tried with many stackoverflow questions but i didnot get answer. Here is my code. Hope someone could solve this issue.
<div class="button-grp">
<button class="icon-button" type="button" onclick="menu(event, '1')"><img
src="../../Images/icons/local_library-white-24dp.svg" class="icon"><br>Learning
</button>
<button class="icon-button" type="button" onclick="menu(event, '2')"><img
src="../../Images/icons/gamepad-white-24dp.svg" class="icon"><br>Tools
</button>
</div>
<div class="sidebar-open">
<div class="main-options" id="0">
<button class="options-button" type="button">Academics</button>
<div class="dropdown-container">
Course Details
Assignments
</div>
<button class="options-button" type="button">Schedule</button>
<div class="dropdown-container">
Exams
Classes
</div>
</div>
</div>
<div id="mainmenu">
Lorem ipsum dolor sit,
</div>
And my Javascript code is as follows..
//function to toggle between clicked buttons and close when double clicked on it.
function menu(evt, id) {
document.querySelectorAll(".main-options").forEach(function(div) {
if (div.id === id) {
// Toggle specified DIV
if(div.style.display === "block"){
div.style.display = "none";
document.getElementById("mainmenu").style.marginLeft = "80px";
document.body.style.backgroundColor = "#fff";
}else{
div.style.display = "block";
document.getElementById("mainmenu").style.marginLeft = "230px";
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
}
} else {
// Hide other DIVs
div.style.display = "none";
}
});
}
//function to hide the dropdown when clicked outside the button.
window.addEventListener('click', function(event){
if (!event.target.matches('.icon-button') ){
var dropdowns = document.getElementsByClassName("main-options");
var i;
for (i = 0; i < dropdowns.length; i++) {
if (dropdowns[i].style.display === "block") {
dropdowns[i].style.display ="none";
document.getElementById("mainmenu").style.marginLeft = "80px";
document.body.style.backgroundColor = "#fff";
}
}
}
});
Why don't you try this:
document.addEventListener("DOMContentLoaded", () => {
document.querySelector(".icon-button").forEach((button) => {
button.addEventListener('click', ()=>{
...
});
});
});

Select elements with all other ID that is not 'this.id'

I have 4 elements and within onclick() only one of the block div will show;
HTML:
<!--elements that will toggle block div to show-->
<p onclick="expand(this.id)" id="p1"></p>
<p onclick="expand(this.id)" id="p2"></p>
<p onclick="expand(this.id)" id="p3"></p>
<p onclick="expand(this.id)" id="p4"></p>
<!--block div-->
<div id="block_p1"></div>
<div id="block_p2"></div>
<div id="block_p3"></div>
<div id="block_p4"></div>
JS:
function expand(e) {
document.getElementById("block_" + e).style.display = "block";
document.getElementById(e).style.backgroundColor = "#425a94";
}
The problem is when I click the second element after the first, says I click p2 after p1, the block div--block_p1 doesn't disappear as block_p2 is shown, how do I hide the first block after the second is clicked? If I didn't use the parameter I'd do something like this:
function expand() {
document.getElementById("block_p2").style.display = "block";
document.getElementById("p2").style.backgroundColor = "#425a94";
document.getElementById("block_p1").style.display = "none";
}
I don't know how to do the same in the case of the one with a parameter. Also in the case that third element is selected I need to hide the first two blocks as well.
You first need to hide all divs that start with id expanded_, just add this line before rest of your code.
var allExpanded = document.querySelectorAll( "div[id^='expanded_']" );
Array.from( allExpanded ).forEach( s => (s.style.display = "none") );
Your functions becomes
function expand(e)
{
//first hide all
var allExpanded = document.querySelectorAll( "div[id^='expanded_']" );
Array.from( allExpanded ).forEach( s => (s.style.display = "none") );
//then show specific
document.getElementById("expanded_" + e).style.display = "block";
document.getElementById(e).style.backgroundColor = "#425a94";
document.getElementById("toolbar_expand").style.display = "block";
}
From my previous answer, a small amendment to pick up all display elements which can be looped over in the function to remove the class that was previously added:
const buttons = document.querySelectorAll('.button');
const slides = document.querySelectorAll('.slide');
buttons.forEach(button => {
button.addEventListener('click', handleClick, false);
});
function handleClick(e) {
const id = e.target.dataset.id;
slides.forEach(slide => slide.classList.remove('show'));
const slide = document.querySelector(`.slide[data-id="${id}"]`);
slide.classList.add('show');
}
.slide {
display: none;
}
.show {
display: block;
}
<p class="button" data-id="1">icon1</p>
<p class="button" data-id="2">icon2</p>
<p class="button" data-id="3">icon3</p>
<div class="slide" data-id="1">blocki1</div>
<div class="slide" data-id="2">blocki2</div>
<div class="slide" data-id="3">blocki3</div>
You can use the id match selector to get all the div with id having block_ as substring and then hide all of them except the clicked one.
function expand(id) {
document.getElementById('block_'+id).style.display = "block";
document.getElementById(id).style.backgroundColor = "#425a94";
document.querySelectorAll('[id^="block_"]').forEach(function(elem){
if(elem.id !== 'block_'+id){
elem.style.display = "none";
var pId = elem.id.split('_')[1];
document.getElementById(pId).style.backgroundColor = "#fff";
}
});
}
div{
display: none;
}
<!--elements that will toggle block div to show-->
<p onclick="expand(this.id)" id="p1">p1 click</p>
<p onclick="expand(this.id)" id="p2">p2 click</p>
<p onclick="expand(this.id)" id="p3">p3 click</p>
<p onclick="expand(this.id)" id="p4">p4 click</p>
<!--block div-->
<div id="block_p1">P1</div>
<div id="block_p2">P2</div>
<div id="block_p3">P3</div>
<div id="block_p4">P4</div>

Use two or more Buttons to Show/hide and replace text in single DIV

I'm building an about us page and I'm hoping to use JavaScript to show/hide/replace a DIV's content with a vision statement or a bio depending on which is clicked by the user. I'm brand new to using script, so I'm hoping there is someone who has done this before.
I currently have a button for the bio and one for the vision and while I'm able to show and hide text with no problem I have no clue how to replace the DIV so that the Bio and Vision don't show at the same time.
Here is what I have so far:
function showhide(id) {
var e = document.getElementById(id);
e.style.display = (e.style.display == 'block') ? 'none' : 'block';
}
<button type="button" onclick="javascript:showhide('vision')">Vision</button>
<button type="button" onclick="javascript:showhide('bio')">Bio</button>
<div id="vision" style="display: none;">
<p>This is my vision</p>
</div>
<div id="bio" style="display: none;">
<p>This is my bio</p>
</div>
I'd also like the button text to change to "Hide Bio" or "Hide Vision" depending on which is revealed as well.
If anyone could help with this it would be GREATLY appreciated for a Java Noob like me.
This is also my first time using a forum like this so any pointers or feedback is appreciated...gotta start somewhere, right?
UPDATE - I attached an image to give a better idea of what I'm try to accomplish.
There are a couple of issues with logic. If you show/hide one div, you'll still need to hide/show the second div. So you can either add more lines of code to do that.. or simply you can use one div and update its content based on the button clicked.
so you can try this:
<script>
var textStrings = {"author1": {"Vision":"this is author1 vision", "Bio":"this is author1 bio"},
"author2": {"Vision":"this is author2 vision", "Bio":"this is author2 bio"},
"author3": {"Vision":"this is author3 vision", "Bio":"this is author3 bio"}};
function showhide(element) {
reset();
var id=element.id;
var author = document.getElementById("authors").elements["authors"].value;
var flag = document.getElementById('content').innerHTML == textStrings[author][id];
document.getElementById('content').innerHTML = flag ? "" : textStrings[author][id];
element.innerHTML = flag ? id : "hide " + id;
}
function reset(){
for (var k in textStrings["author1"]){
document.getElementById(k).innerHTML = k;
}
}
function resetAuthor(){
document.getElementById('content').innerHTML = ""
reset();
}
</script>
<form id="authors">
<input type="radio" name="authors" id="author1" onchange="resetAuthor()" value="author1" checked> author 1
<input type="radio" name="authors" id="author2" onchange="resetAuthor()" value="author2"> author 2
<input type="radio" name="authors" id="author3" onchange="resetAuthor()" value="author3"> author 3
</form>
<div style="display:inline">
<button type="button" id="Vision" onclick="javascript:showhide(this)">Vision</button>
<button type="button" id="Bio" onclick="javascript:showhide(this)">Bio</button>
</div>
<div style="display: block;">
<p id="content"></p>
</div>
This code also toggles/set contents as empty if you hit the button again.
DEMO
Try to pass the this object into the inline event handler and check the content's display state to toggle the button's text,
HTML:
<button type="button" onclick="javascript:showhide('vision',this)">Vision</button>
<button type="button" onclick="javascript:showhide('bio',this)">Bio</button>
<div id="vision" style="display: none;">
<p>This is my vision</p>
</div>
<div id="bio" style="display: none;">
<p>This is my bio</p>
</div>
JS
function showhide(id,elem) {
var e = document.getElementById(id);
var cond = (e.style.display == 'block');
e.style.display = cond ? 'none' : 'block';
elem.textContent = (id == "vision") ? (cond ? "Show Vision" : "Hide Vision")
: (cond ? "Show Bio" : "Hide Bio");
}
DEMO
Try this out.
var prevPage = "";
var currPage = "";
function showhide(event) {
prevPage = currPage;
currPage = event.id.split("_")[1];
if(prevPage !== currPage){
showEle(currPage);
if(prevPage !== ''){
hideEle(prevPage);
}
} else {
toggle(currPage);
}
}
function toggle(id){
var curr = document.getElementById(id);
if(curr.style.display === 'block'){
curr.style.display = 'none';
updateBtn('btn_'+id, 'Show');
} else {
curr.style.display = 'block';
updateBtn('btn_'+id, 'Hide');
}
}
function updateBtn(id, newStr){
var btn = document.getElementById(id);
btn.innerHTML = newStr + ' ' + btn.innerHTML.split(' ')[1];
}
function showEle(id){
document.getElementById(id).style.display = 'block';
updateBtn('btn_'+id, 'Hide');
}
function hideEle(id){
document.getElementById(id).style.display = 'none';
updateBtn('btn_'+id, 'Show');
}
<button id="btn_vision" type="button" onclick="showhide(this)">Show Vision</button>
<button id="btn_bio" type="button" onclick="showhide(this)">Show Bio</button>
<button id="btn_xyz" type="button" onclick="showhide(this)">Show Xyz</button>
<button id="btn_abc" type="button" onclick="showhide(this)">Show Abc</button>
<div id="vision" style="display: none;">
<p>This is my vision</p>
</div>
<div id="bio" style="display: none;">
<p>This is my bio</p>
</div>
<div id="xyz" style="display: none;">
<p>This is my xyz</p>
</div>
<div id="abc" style="display: none;">
<p>This is my abc</p>
</div>
Note: You might want to initialize the currPage with the first page's id since it gives a better feel.
Say currPage = "vision" and also make display block for div id = "vision".

Categories

Resources