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>
Related
I got problem with my accordion script. I'm trying to create accordion looking like this in screen
var accordionItem = document.querySelectorAll('.accordion-item');
var accordionContent = document.querySelectorAll('.accordion-item_content');
var accordionButton = document.querySelectorAll('.accordion-btn');
for (i = 0; i < accordionButton.length; i++) {
accordionButton[i].addEventListener('click', () => {
accordionContent[i].classList.add('opnen')
})
}
<div class="accordion-item">
<div class="accordion-item_header">
<h3>Experience</h3>
<button class="accordion-btn">+</button>
</div>
<div class="accordion-item_content container">
</div>
</div>
After click on my button i got console error
I want to open my content box after clicking only button in accordion header div. How to do it?
Issue:
Your i variable is globallly scoped, therefore at the time you click it — its value already incremented to 1 - and there's no such accordionContent[1] element.
Solution:
Scope your variable using the let keyword: let i = 0;
var accordionItem = document.querySelectorAll('.accordion-item');
var accordionContent = document.querySelectorAll('.accordion-item_content');
var accordionButton = document.querySelectorAll('.accordion-btn');
for (let i = 0; i < accordionButton.length; i++) {
accordionButton[i].addEventListener('click', () => {
accordionContent[i].classList.add('open');
});
}
.accordion-item_content { display: none; }
.accordion-item_content.open { display: block; }
<div class="accordion-item">
<div class="accordion-item_header">
<h3>Experience</h3>
<button class="accordion-btn" type="button" aria-label="Toggle content">+</button>
</div>
<div class="accordion-item_content container">content here</div>
</div>
Anyways, I might suggest you another way to implement the desired, and that's by using data-* attribute selectors like in this related answer: Toggle elements on buttons click or Dropdown Menu Toggle
Or by using the Details element
<details>
<summary>Experience</summary>
content here
</details>
I am trying to add an increasing count number when a button is clicked, within the container <div>.
My code is not working, what am I missing?
let taskCounter = 0;
let addTaskFunction = () => {
const container = document.querySelector(".container");
taskCounter++;
let counterInDiv = document.createElement(`<div> ${taskCounter} </div>`);
container.appendChild(counterInDiv);
};
document.getElementById('addTask').addEventListener("click", () => {
addTaskFunction();
});
<h1>Your tasklist for today</h1>
<div class="container">
<div class="inputPart">
<input id="taskInput" value="" placeholder="Fill in the following task here" />
<button id="addTask">Add task</button>
<button id="removeAllTasks">Delete tasks</button>
</div>
</div>
You need to use the tag name (div) for document.createElement then set the innerHTML instead of using the actual HTML code.
let taskCounter = 0;
let addTaskFunction = () => {
const container = document.querySelector(".container");
taskCounter++;
let counterInDiv = document.createElement("div"); // <--HERE
counterInDiv.innerHTML = taskCounter;
container.appendChild(counterInDiv);
};
document.getElementById('addTask').addEventListener("click", () => {
addTaskFunction();
});
<body>
<h1>Your tasklist for today</h1>
<div class="container">
<div class="inputPart">
<input id="taskInput" value="" placeholder="Fill in the following task here" />
<button id="addTask">Add task</button>
<button id="removeAllTasks">Delete tasks</button>
</div>
</div>
<script src="app.js"></script>
</body>
I believe that this is the code you want:
let taskCounter = 1;
const taskList = document.getElementById("taskList");
const addTaskBtn = document.getElementById("addTask");
addTaskBtn.addEventListener("click", () => {
let task = document.getElementById("taskInput").value;
let counterInDiv = document.createElement("div");
counterInDiv.textContent = `${taskCounter++}: ${task}`;
taskList.appendChild(counterInDiv);
});
const deleteTasksBtn = document.getElementById("removeAllTasks");
deleteTasksBtn.addEventListener("click", () => {
taskList.innerHTML = "";
taskCounter = 1;
});
<h1>Your tasklist for today</h1>
<div class="container">
<div class="inputPart">
<input id="taskInput" placeholder="Fill in the following task here" />
<button id="addTask">Add task</button>
<button id="removeAllTasks">Delete tasks</button>
</div>
<div id="taskList"></div>
</div>
I made a few changes:
You do not need a function for the event listener, you can put the code inside an anonymous function that is passed to the event listener
taskCounter should start at 1, not 0
If you want the delete tasks button to work, then you should put the tasks inside a different container that can be easily cleared. I used one with the ID of "taskList"
document.querySelector() only selects a single element, but you gave it a class of "container". If multiple <div>s have the class "container", then you will run into problems.
document.createElement takes a tag name as the parameter, not HTML code. You should use document.createElement("div") then set the .textContent to whatever you want.
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'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();
}
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>