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>
Related
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');
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>
I'm learning JavaScript and this is a practice scenario for me.
What I have already is a button that clones content, and within that content that has been cloned, there is a button to remove it.
When I click the button that prompts you to remove the content, it removes the first set of content.
What I want to happen is when you click the button that prompts you to remove the content, it removes the content related to that button and nothing else.
This is the CodePen link.
https://codepen.io/JosephChunta/pen/YzwwgvQ
Here is the code.
function addContent() {
var itm = document.getElementById("newContent");
var cln = itm.cloneNode(true);
document.getElementById("placeToStoreContent").appendChild(cln);
}
function removeContent() {
var x = document.getElementById("content").parentNode.remove();
}
// This is for debug purposes to see which content is which
document.getElementById('orderContent')
.addEventListener('click', function(e) {
const orderedNumber = document.querySelectorAll('.thisIsContent');
let i = 1;
for (p of orderedNumber) {
p.innerText = '' + (i++);
}
});
.contentThatShouldBeHidden {
display: none;
}
<div id="placeToStoreContent">
</div>
<button id="orderContent" onclick="addContent()">Add Content</button>
<div class="contentThatShouldBeHidden">
<div id="newContent">
<div id="content">
<p class="thisIsContent">This is a prompt</p>
<button onclick="removeContent()">Remove this</button>
<hr />
</div>
</div>
</div>
When you'r trying to remove by ID, it takes the first ID it finds.
To remove the correct content, send this onclick.
<button onclick="removeContent(this)">Remove this</button>
And handle it in your function:
function removeContent(el) {
el.parentNode.remove();
}
Example:
function addContent() {
var itm = document.getElementById("newContent");
var cln = itm.cloneNode(true);
document.getElementById("placeToStoreContent").appendChild(cln);
}
function removeContent(el) {
el.parentNode.remove();
}
// This is for debug purposes to see which content is which
document.getElementById('orderContent')
.addEventListener('click', function(e) {
const orderedNumber = document.querySelectorAll('.thisIsContent');
let i = 1;
for (p of orderedNumber) {
p.innerText = '' + (i++);
}
});
.contentThatShouldBeHidden { display: none; }
<div id="placeToStoreContent">
</div>
<button id="orderContent" onclick="addContent()">Add Content</button>
<div class="contentThatShouldBeHidden">
<div id="newContent">
<div id="content">
<p class="thisIsContent">This is a prompt</p>
<button onclick="removeContent(this)">Remove this</button>
<hr />
</div>
</div>
</div>
In your remove button, do this:
<!-- The "this" keyword is a reference to the button element itself -->
<button onclick="removeContent(this)">Remove this</button>
And in your javascript:
function removeContent(element) {
element.parentNode.remove();
}
OUTLOOK:
I have a website which has a page called questions.html . In the page , there are many questions with answers. Each question is a div element. The answers is also a div and are hidden initially and is visible only when a button is clicked.
ATTEMPT & PROBLEM:
I have done it successfully for one set of question and answer , but when I do the same for another set the whole system gets messy. When I click on the button on the second question div , the answer div of the first question div shows up. But I want the button on the second question div to open the answer div of the second question div.
HTML :
<div id = "question1">
<div id = "answer1" style = "display:none;">This is the 1st answer</div>
<button id = "button1" onClick = "show()">Click For Answer</button>
</div>
<div id = "question2">
<div id = "answer2" style = "display:none;">This is the 1st answer</div>
<button id = "button2" onClick = "show()">Click For Answer</button>
</div>
JavaScript :
function show()
{
var div=document.getElementById("answer1");
var button=document.getElementById("button1");
div.style.display="block";
button.style.display="none";
}
I also noticed that it happens because my variables div and button wont select the div with the next set of ids (answer2 and button2)
MY APPROACH:
So I thought of creating a new function for each set of question and answer div. But this seems very unprofessional.
So is there any other way?
Thanks for the help :)
Pass the IDs as arguments:
function show(answerID, buttonID)
{
var div=document.getElementById(answerID);
var button=document.getElementById(buttonID);
div.style.display="block";
button.style.display="none";
}
Then the HTML would be:
<div id = "question1">
<div id = "answer1" style = "display:none;">This is the 1st answer</div>
<button id = "button1" onClick = "show('answer1', 'button1')">Click For Answer</button>
</div>
<div id = "question2">
<div id = "answer2" style = "display:none;">This is the 1st answer</div>
<button id = "button2" onClick = "show('answer2', 'button2')">Click For Answer</button>
</div>
If you can use jQuery,
$(".show-answer").on("click", function() {
$(this).siblings(".answer").css("display", "block");
$(this).css("display", "none");
});
.answer {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="question">
<div class="answer">This is the 1st answer</div>
<button class="show-answer">Click For Answer</button>
</div>
<div class="question">
<div class="answer">This is the 1st answer</div>
<button class="show-answer">Click For Answer</button>
</div>
Selection process becomes simple and HTML looks clean.
use previoussibling to show answers div and pass this for button
update there is problem with previoussibling that it consider text as node also so i have provided a function in working demo that can be used to overcome that problem
function show(obj)
{
var div=obj.previousSibling;
var button=obj
div.style.display="block";
button.style.display="none";
}
<div id = "question1">
<div id = "answer1" style = "display:none;">This is the 1st answer</div><button id = "button1" onClick = "show(this)">Click For Answer</button>
</div>
<div id = "question2">
<div id = "answer2" style = "display:none;">This is the 1st answer</div><button id = "button2" onClick = "show(this)">Click For Answer</button>
</div>
function show(obj)
{
console.log(obj.previousSibling)
var div=previousElementSibling(obj);
var button=obj
div.style.display="block";
button.style.display="none";
}
function previousElementSibling( elem ) {
do {
elem = elem.previousSibling;
}
while ( elem && elem.nodeType !== 1 );
return elem;
}
<div id = "question1">
<div id = "answer1" style = "display:none;">This is the 1st answer</div><button id = "button1" onClick = "show(this)">Click For Answer</button>
</div>
<div id = "question2">
<div id = "answer2" style = "display:none;">This is the 1st answer</div><button id = "button2" onClick = "show(this)">Click For Answer</button>
</div>
You don't need all that ID / class trickery,
also using inline JS is quite hard to maintain.
See this instead, where I've only used class="qa"
var qa = document.getElementsByClassName("qa");
function show(){
this.parentNode.getElementsByTagName("DIV")[0].style.display = (this.clicked^=1) ? "block" : "none";
}
for(var i=0; i<qa.length; i++)
qa[i].getElementsByTagName("BUTTON")[0].addEventListener("click", show, false);
div.qa > div{
display:none;
}
<div class="qa">
<div>This is the 1st answer</div>
<button>Click For Answer</button>
</div>
<div class="qa">
<div>This is the 1st answer</div>
<button>Click For Answer</button>
</div>
You can even use pure CSS for this, by just replacing button with a and usign the :target pseudo selector
div.qa > div{
display:none;
}
div.qa > div:target{
display:block;
}
<div class="qa">
<div id="one">This is the 1st answer</div>
Click For Answer
</div>
<div class="qa">
<div id="two">This is the 2nd answer</div>
Click For Answer
</div>
I have some links that will show a div when clicking it. When clicking another link, it should show the link's associated div and hide the previously shown div.
HTML
Text 1
Text 2
Text 3
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
Javascript
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
CSS
.hidden { display: none; }
.unhidden { display: block; }
How can I accomplish this?
Try with:
function unhide(divID) {
var unhidden = document.getElementsByClassName('unhidden');
for (var k in unhidden) {
unhidden[k].className='hidden';
}
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
You can do something like this :
function unhide(divID) {
var divs = document.getElementsByTagName('div');
foreach(var div in divs){
div.className = 'hidden';
if(div.id == divID)
div.className = 'unhidden';
}
}
Be careful with document.getElementsByTagName('div');, it will return you all divs on your document. You could adapt it using a wrapper.
For example :
HTML
<div id="wrapper">
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
</div>
JS :
var divs = document.getElementById('wrapper').getElementsByTagName('div');
Try this http://jsfiddle.net/L79H7/1/:
function unhide(divID) {
var divIds = [ "text1", "text2", "text3" ];
for ( var i = 0, len = divIds.length; i < len; i++) {
var item = document.getElementById(divIds[i]);
if (item) {
item.className = divID == divIds[i] ? 'unhidden' : 'hidden';
}
}
}
You could also store in an array the names of the divs you want to hide and iterate over it when unhiding one:
var divs= new Array("text1", "text2", "text3");
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
for (var i in divs){
if (divs[i] != divID){
item = document.getElementById(divs[i]);
if (item) {
item.className='hidden';
}
}
}
}
JSFiddle
You don't need exactly links for this, but if you insist change it to:
<a href="#" onclick='unhide("text3");'>Text 3</a>
Otherwise you can change it to:
<p onclick="unhide('text1')">Text 1</p>
<p onclick="unhide('text2')">Text 2</p>
<p onclick="unhide('text3')">Text 3</p>
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
And your function should look like this to add or remove classes:
function unhide(id){
yourElement = document.getElementById(id);
if(yourElement.className == "unhidden"){
yourElement.className = "hidden";
}else{
yourElement.className = "unhidden";
}
}
demo
<div id="text1" class="hidden"> 1 </div>
<div id="text2" class="hidden"> 2 </div>
<div id="text3" class="hidden"> 3 </div>
.hidden{ display:none; }
#text1{ display: block; }
function show(id) {
var item = document.getElementById(id);
var all = document.getElementsByClassName('hidden');
for(var i=0; i<all.length; i++)all[i].style.display = 'none';
if(item)item.style.display = 'block';
}
you can use jquery try the code below and import the jquery library first
$('#text1').show();
$('#text2').hide();
it is the easiest way