How to hide/reveal a block when clicking on one button? - javascript

function questionDisplay() {
let qBtn = document.querySelector(".question");
let qTextShow = document.createElement("div");
qBtn.addEventListener("click", ifElse)
function ifElse() {
if(qBtn !== true) {
qTextShow.className = "info_q";
qTextShow.innerHTML = `text`
qBtn.appendChild(qTextShow);
qTextShow.style.display = "block"
} else {
qTextShow.style.display = "none"
}
}
}
questionDisplay()
The qBtn button opens a div with text, but does not hide this block when clicking on it, how to fix it?

The most common way is to write your code in your HTML, rather than creating the element with document.createElement(), hiding it by default with CSS utility. class, then use .classList.toggle() to toggle that utility class. Like this:
const some_el = document.getElementById('some_id');
document.getElementById('show_text').addEventListener('click', () => some_el.classList.toggle('hidden'));
.hidden {
display: none;
}
<div id="some_id" class="hidden">
Some text
</div>
<button id="show_text">Show text</button>

What you have to do in the if is to check if the div you want to appear/disappear is block or not. One way to do this is to use the getComputedStyle() method, which returns the computed values of all CSS properties of an element.
function questionDisplay() {
let qBtn = document.querySelector(".question");
let qTextShow = document.createElement("div");
qBtn.addEventListener("click", ifElse)
function ifElse() {
let computedStyle = window.getComputedStyle(qTextShow);
let display = computedStyle.getPropertyValue("display");
if(display === "none") {
qTextShow.className = "info_q";
qTextShow.innerHTML = `text`
qBtn.appendChild(qTextShow);
qTextShow.style.display = "block"
} else {
qTextShow.style.display = "none"
}
}
}
questionDisplay()

function myFunction() {
var element = document.getElementById("myDIV");
element.classList.toggle("mystyle");
}
#myDIV {
display: none
}
#myDIV.mystyle {
display: block
}
<button onclick="myFunction()">Try it</button>
<div id="myDIV">
This is a DIV element.
</div>

You can try out this piece of code where hiding and showing an element is done using css classes by the display property of a particular element.
const element = document.querySelector("#element");
const button = document.querySelector(".btn");
button.addEventListener("click",() => {
element.classList.toggle("hide");
})
.hide{
display : none;
}
<div id="element"> This is an element to hide or show </div>
<button class="btn"> Click Me </button>

Related

How do I toggle DOM elements to show and hide

On my index.JS file, I created elements using documentCreateElement and appended them to the DOM to show data from an api. Then I created an event listener which works where if I click my H3 element, it will show my H4 and P element. But I want it to where if I click my H3 element again, I want the H4 and P elements to hide. This is the code I have for my click event listener:
`H3.addEventListener(‘click’, clickFunction)
Function clickFunction() {
Div.append(h4)
Div.append(p)
}`
Can someone please help me?
I tried to look up toggling functions online or incorporate CSS hidden class to the h4 and p elements but nothing was hiding
Try modifying your clickFunction() to check if the elements are already displayed or not.
let isDisplayed = false;
function clickFunction() {
if (isDisplayed) {
// If the elements are already displayed, hide them
h4.style.display = "none";
p.style.display = "none";
isDisplayed = false;
} else {
// If the elements are not displayed, show them
div.appendChild(h4);
div.appendChild(p);
isDisplayed = true;
}
}
h3.addEventListener("click", clickFunction);
In above example, its a boolean variable isDisplayed to keep track of whether the elements are currently displayed or not. When the h3 element is clicked, the clickFunction() is called, and it checks the value of isDisplayed. If its true, it means the elements are already displayed, so we hide them by setting their display style to "none" and setting isDisplayed to false. If it's false, it means the elements are not displayed, so we show them by appending them to the div and setting isDisplayed to true.
Note that you'll need to deeclare the isDisplayed variable outside of the clickFunction() so that its value is preserved between function calls. And make sure to select the h4, p, and div elements using document.querySelector() or a smilar method before using them in the function.
You can try this in your clickFunction
Function clickFunction() {
if(!Div.hasChildNodes()) {
Div.append(h4)
Div.append(p)
} else {
Div.removeChild(Div.childNodes(0))
Div.removeChild(Div.childNodes(1))
}
}
Check this for more info.
Follow the below steps-
Find the existing p and h4 elements.
If found then remove those using the removeChild method, else append those using the append method.
Here is a working demo of toggling the elements-
let h3 = document.querySelector('h3');
h3.addEventListener('click', clickFunction)
let div = document.querySelector('div');
function clickFunction() {
// Find already exists p and h4 elements
let p_exists = document.querySelector('p');
let h4_exists = document.querySelector('h4');
// If found then remove one by one
if (p_exists && h4_exists) {
div.removeChild(h4_exists);
div.removeChild(p_exists);
}
// Else, create and append
else {
let h4 = document.createElement('h4')
h4.innerText = "I am a h4 element";
let p = document.createElement('p')
p.innerText = "I am a p element";
div.append(h4, p);
}
}
<h3>Click</h3>
<div></div>
Using a CSS style rule and checking for the existence of the CSS style rule class name on each HTML element's class list is a common method for toggling the display state of an element.
I used a hide class name in the code snippet but you can change to a 'show' class name with some minor modifications to the code and CSS rules.
var H3 = document.getElementById("h3-elem");
H3.addEventListener("click", clickFunction);
var Div = document.getElementById("div-elem");
function clickFunction() {
var h4 = document.getElementById("h4-elem");
var p = document.getElementById("p-elem");
if (!h4) {
h4 = appendH4();
}
if (!p) {
p = appendP();
}
// Option 1:
// Use the built-in 'toggle()' method on the class list
// for each element.
// https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle
// h4.classList.toggle("hide");
// p.classList.toggle("hide");
// Option 2:
// Check if the class list for the 'h4' and 'p' elements
// contain 'hide' class name. If the class list does not
// contain the class name then add the 'hide' class name
// to the class list.
if (h4.classList.contains("hide")) {
h4.classList.remove("hide");
} else {
h4.classList.add("hide");
}
if (p.classList.contains("hide")) {
p.classList.remove("hide");
} else {
p.classList.add("hide");
}
}
// Set to hide initially. After creation of the element,
// the 'clickFunction' will determine the display state
// of the element by checking for the existense of the
// 'hide' class name.
function appendH4() {
var h4 = document.createElement("h4");
h4.id = "h4-elem";
h4.className = "hide";
h4.textContent = "Header 4";
Div.append(h4);
return h4;
}
function appendP() {
var p = document.createElement("p");
p.id = "p-elem";
p.className = "hide";
p.textContent = "A paragraph";
Div.append(p);
return p;
}
.hide {
display: none;
}
<h3 id="h3-elem">Header 3</h3>
<div id="div-elem"></div>

How can I click on a div and have it open a targeted div, then have the targeted div close when i click on a 3rd div?

I have a gallery of 20 images and each image corresponds to a div with text in it.
When i click on an image, the text should appear. When i click on the next image, that images text should appear WHILE closing the previous text div from the 1st image i clicked on.
So only one text box should be visible at one time.
so far i have this:
attachToggleListener("leifr","rosenvold");
attachToggleListener("damians","smith");
attachToggleListener("megan","adam");
function attachToggleListener (buttonID, divID) {
var myTrigger = document.getElementById(buttonID);
if (myTrigger != null) {
myTrigger.addEventListener("click", toggleDiv);
myTrigger.targetDiv = divID;
}
}
function toggleDiv(evt) {
var target = document.getElementById(evt.currentTarget.targetDiv);
if (target.style.display === "block")
{ target.style.display = "none"; }
else
{ target.style.display = "block"; }
}
the text appears when i click on the image, but it does not close when i click on the next image.
as it sits now, I can click on 4 images and 4 text divs will appear and only be removed when i click the image that made it appear.
Again what i was expecting was to click on an image "leifr" > the text box appears "rosenvold" >click on a second image "damians" > the second text box appears "smith" while the 1st text box "rosenvold" disappears
You can modify your toggleDiv function to read all possible divs. I would suggest you to do 2 things.
Add a class to your divs. Say for example image_helper_text.
Modify your toggleDiv function to look something like
function toggleDiv(evt) {
var target = document.getElementById(evt.currentTarget.targetDiv);
var targets = document.getElementsByClassName("image_helper_text");
// This will remove all other divs.
if (targets && Array.isArray(targets) && targets.length) {
targets.forEach((each) => {
if (
each.id !== evt.currentTarget.targetDiv &&
each.style.display === "block"
) {
each.style.display = "none";
}
});
}
if (target.style.display === "block") {
target.style.display = "none";
} else {
target.style.display = "block";
}
}
Here's a basic example on how you can toggle between image captions. You have to keep track of the currently visible image caption (previousCaption) and then when a new image is clicked, simply hide previousCaption and display the new one.
const images = document.querySelectorAll(".image");
let previousCaption = null; //currently visible image caption
images.forEach((img) => {
const caption = img.querySelector(".caption");
img.addEventListener("click", () => {
if (previousCaption) previousCaption.classList.toggle("hide");
caption.classList.toggle("hide");
previousCaption = caption;
});
});
body {
display: flex;
height: 100vh;
width: 100vw;
align-items: center;
justify-content: center;
gap: 1em;
}
.image {
height: 100px;
width: 100px;
outline: 1px solid;
}
.hide {
visibility: hidden;
}
<div class="image">
<div class="caption hide">caption1</div>
</div>
<div class="image">
<div class="caption hide">caption2</div>
</div>
<div class="image">
<div class="caption hide">caption3</div>
</div>
RESPONSE
Here is another way to do it.
HTML
<button data-target-id="470bec9d-a334-46cb-a7ff-01f4369120a7">Show Image #1</button>
<div id="470bec9d-a334-46cb-a7ff-01f4369120a7" class="">
<label>Image #1</label>
<img src="https://cdn-icons-png.flaticon.com/512/8711/8711519.png">
</div>
<br>
<br>
<!-- ... etc ... -->
CSS
img {
max-width: 100px;
}
div {
display: none;
}
div.show {
display: block;
}
JS
// Data
const dataList = [
{ image: 'https://cdn-icons-png.flaticon.com/512/8711/8711519.png', text: 'Image #1' },
{ image: 'https://cdn-icons-png.flaticon.com/512/8711/8711531.png', text: 'Image #2' },
{ image: 'https://cdn-icons-png.flaticon.com/512/8711/8711524.png', text: 'Image #3' },
{ image: 'https://cdn-icons-png.flaticon.com/512/8711/8711522.png', text: 'Image #4' },
{ image: 'https://cdn-icons-png.flaticon.com/512/8711/8711521.png', text: 'Image #5' },
];
// Loop through data and render on screen
for (const data of dataList) {
const { image, text } = data;
// Generate Random ID
const id = crypto.randomUUID();
// Create Button
const btn = document.createElement('button');
btn.setAttribute('data-target-id', id);
btn.innerText = `Show ${text}`;
document.body.appendChild(btn);
// Create Div with data
const el = document.createElement('div');
el.setAttribute('id', id);
el.innerHTML = `<label>${text}</label><img src="${image}">`;
document.body.appendChild(el);
// Create Spacers ( new lines )
const br = document.createElement('br');
document.body.appendChild(br.cloneNode());
document.body.appendChild(br.cloneNode());
}
// Attach Event Listener to buttons
function attachButtonListeners() {
const buttons = document.getElementsByTagName('button');
for (const button of buttons) {
button.addEventListener('click', toggleShowHide);
}
}
// show / hide div with data
function toggleShowHide({ target }={}) {
const { targetId } = target.dataset;
const div = document.getElementById(targetId);
if (div.classList.contains('show')) {
div.classList.remove('show')
} else {
div.classList.add('show')
}
}
// Run event listener
attachButtonListeners();

how to change style display background image url

function btnclick() {
var btn = document.getElementById('M_menucol').style.display;
if (btn == 'none')
{
document.getElementById('M_menucol').style.display = 'block';
document.getElementById('M_menubtn').style.backgroundImage = "url(.../image/cancel.png)";
}
else {
document.getElementById('M_menucol').style.display = 'none';
document.getElementById('M_menubtn').style.backgroundImage = "url(.../image/menubtn.png)";
}
};
i want change display none to block and reverse + backgroundimage url
display change is working but background image change dont working
plz give me solution...
sorry for my bad english
I'm sorry my meaning was that when I click the button it opens a menu, and the button's image changes. Clicking the button again closes the menu and returns the image to its original state.
And I will study hard ;)
https://jsfiddle.net/phnzb10m/12/
Here is how I would do this:
function btnclick() {
var btn = document.getElementById('M_menucol');
if(btn != null) {
btn.classList.toggle("cancel")
}
};
The style.css file would contain something like this:
#M_menucol{
display: none;
background-image: url(.../image/menubtn.png);
}
.cancel{
display: block;
background-image: url(.../image/cancel.png);
}
In your fiddle why do you separated col, btn with comma when you setting the style of them ? i think you mean semicolon instead
In your fiddle the element id is Mmenubtn while you write it M_menubtn in the script
you should know that style is an object of elements so it's cannot output the style sets by style or link tags it's just output inline style or style sets to it by js
if you want to get style sets by style or link tags you will be need to use getComputedStyle() method
by default when there's no any inline style the values of style object properties is empty string so you can check if it's return empty string or none then execute you script
By Display Property
function btnclick() {
var col = document.getElementById('M_menucol');
var btn = document.getElementById('M_menubtn');
if (col.style.display === "" || col.style.display == 'none') {
col.style.display = 'block'
btn.style.backgroundImage = "url(https://postimg.cc/68V0PW0t)";
} else {
col.style.display = 'none'
btn.style.backgroundImage = "url(https://i.postimg.cc/vBVMcpmM/menubtn.png)";
}
}
By getComputedStyle() Method
function btnclick() {
var col = document.getElementById('M_menucol');
var btn = document.getElementById('M_menubtn');
if (getComputedStyle(col, null).display == 'none') {
col.style.display = 'block';
btn.style.backgroundImage = "url(https://postimg.cc/68V0PW0t)";
} else {
col.style.display = 'none';
btn.style.backgroundImage = "url(https://i.postimg.cc/vBVMcpmM/menubtn.png)";
}
}

Detect if all children are hidden and hide parent div using vanilla JS

As the title suggests, I wwant to build a filter that hides elements. If all children are hidden then the paretn should also set itself to display none only I can't quite figure out how to approach it. I've tried the below with no luck.
https://jsfiddle.net/6wt0jndp/1/
function filter(e){
search = e.value.toLowerCase();
console.log(e.value)
document.querySelectorAll('.kb-item').forEach(function(row){
text = row.innerText.toLowerCase();
if(text.match(search)){
row.style.display="block"
} else {
row.style.display="none"
}
// need to count hidden items and if all instances of .kb-items are hidden, then hide .kb-item
var countHidden = document.querySelectorAll(".kb-item[style='display: none;']").length;
var children = document.querySelectorAll(".kb-items").length;
if(countHidden > children){
row.style.display="none"
}
console.log(countHidden);
})
}
HTML
<div class="kb-items">
<h1>fruits</h1>
<div class="kb-item">apple</div>
<div class="kb-item">banana</div>
</div>
<div class="kb-items">
<h1>vegetables</h1>
<div class="kb-item">lettuce</div>
<div class="kb-item">onion</div>
<div class="kb-item">carrot</div>
</div>
may be you can trigger two function on keypress . One would detect the elements state in a group which will detect whether all the element is hidden or not. We can edit the below code a bit for dom efficency.
Hope this is the result what you are expecting
fiddle link : https://jsfiddle.net/binaryslate/2z1ptnao/1/
<input type="text" onkeyup="filter(this);detectParent();"/>
function detectParent()
{
var collectionref=document.querySelectorAll(".kb-items");
collectionref.forEach(group=>{
var itemcollection=group.getElementsByClassName("kb-item");
var hidecounter=0;
for(var j=0;j<itemcollection.length;j++)
{
if(itemcollection[j].style.display==='none')
{
hidecounter++;
}
}
if(hidecounter===itemcollection.length)
{
group.style.display="none";
}else{
group.style.display="block";
}
});
}
You need to do things to parent after iterating children, not during doing it.
Get children for each parent they have, not whole .kb-item elements.
Compare the length of children and length of them with display: none style.
function filter(e) {
// ...
var parents = document.querySelectorAll(".kb-items");
parents.forEach(parent => {
if (parent.querySelectorAll(".kb-item").length == parent.querySelectorAll(".kb-item[style='display: none;']").length) {
parent.style.display = "none"
} else {
parent.style.display = "block"
}
})
Complete code snippet:
function filter(e) {
search = e.value.toLowerCase();
console.log(e.value)
document.querySelectorAll('.kb-item').forEach(function(row) {
text = row.innerText.toLowerCase();
if (text.match(search)) {
row.style.display = "block"
} else {
row.style.display = "none"
}
})
var parents = document.querySelectorAll(".kb-items");
parents.forEach(parent => {
if (parent.querySelectorAll(".kb-item").length == parent.querySelectorAll(".kb-item[style='display: none;']").length) {
parent.style.display = "none"
} else {
parent.style.display = "block"
}
})
}
<input type="text" onkeyup="filter(this)" />
<div class="kb-items">
<h1>fruits</h1>
<div class="kb-item">apple</div>
<div class="kb-item">banana</div>
</div>
<div class="kb-items">
<h1>vegetables</h1>
<div class="kb-item">lettuce</div>
<div class="kb-item">onion</div>
<div class="kb-item">carrot</div>
</div>

How to hide current content by clicking outside its area, and when I show another content in IE11?

Clicking on the button shows and hides the corresponding content.
function funC(id) {
var el = document.getElementById(id);
if(el.style.display == 'inline-block')
el.style.display = '';
else
el.style.display = 'inline-block';
}
button {margin:2px; outline:0; font-size:12px;}
span {padding:2px; border:1px solid silver;
font-size:12px;}
.cb {display:none;}
<button onclick="funC('cnt1');">b1</button><span id="cnt1" class="cb">content b1...</span>
<br />
<button onclick="funC('cnt2');">b2</button><span id="cnt2" class="cb">content b2...</span>
<br />
<button onclick="funC('cnt3');">b3</button><span id="cnt3" class="cb">content b3...</span>
fiddle example
1. But, how to hide content when clicking outside its area,
and as with showing the next content, hide the previous one?
2. Is it possible to do the same without using id?
Only pure javascript. Thank you.
This might not be a perfect solution but here is a proposition :
function hideAllContent() {
var elements = document.querySelectorAll(".cb");
for(var i =0, l = elements.length; i < l; i++) {
var element = elements[i];
element.visible = false;
element.style.display='none';
}
}
function funC(id, event) {
// We need to stop the event to avoid bubling until the body
event.stopPropagation();
// let's hide others before displaying the new one
hideAllContent();
var el = document.getElementById(id);
if(el.visible) {
el.visible = false;
el.style.display = 'none';
} else {
el.visible = true;
el.style.display = 'inline-block';
}
}
document.body.onclick = function(event) {
if (!event.target.classList.contains('cb')) {
hideAllContent();
}
}
button {margin:2px; outline:0; font-size:12px;}
span {padding:2px; border:1px solid silver;
font-size:12px;}
.cb {display:none;}
<button onclick="funC('cnt1', event);">b1</button><span id="cnt1" class="cb">content b1...</span>
<br />
<button onclick="funC('cnt2', event);">b2</button><span id="cnt2" class="cb">content b2...</span>
<br />
<button onclick="funC('cnt3', event);">b3</button><span id="cnt3" class="cb">content b3...</span>
About avoiding ids, you could use the target property on click event and find the sibling node or something like that or use a querySelector. But ids are safe and fine i would say.
No inline on-clicks attached.
No IDs use.
Used backward-compatible syntax for IE 11.
// JavaScript
// get all button and span tags
var btns = document.querySelectorAll('button');
var otherSpans = document.querySelectorAll('span');
// Detect all clicks on the document
document.addEventListener("click", function(event) {
const spanElems = document.querySelectorAll('span');
const spanElemsArray = Array.prototype.slice.call(spanElems);
let matches = event.target.matches ? event.target.matches('button') : event.target.msMatchesSelector('button');
// If user clicks inside the element, do nothing
if (matches) {
return;
} else {
// If user clicks outside the element, hide it!
spanElemsArray.forEach( function (spanElem) {
spanElem.classList.remove("open");
});
}
});
// convert buttons and spans variable objects to arrays
const btnsArray = Array.prototype.slice.call(btns);
const otherSpansArray = Array.prototype.slice.call(otherSpans);
// loop through every button and assign a click to each one
btnsArray.forEach( function (btn) {
btn.addEventListener('click', spanFunc)
});
// Pass the button clicked as a reference
function spanFunc(){
openSpan(this);
}
// toggle the display class on the span next to the button using nextElementSibling method
function openSpan(e) {
e.nextElementSibling.classList.toggle("open");
// hide every other spans
function otherSpanFunc() {
otherSpansArray.forEach( function (otherSpan) {
if (otherSpan !== e.nextElementSibling) {
otherSpan.classList.remove('open');
}
});
}
otherSpanFunc();
}
/* css */
button {margin:2px; outline:0; font-size:12px;}
span {padding:2px; border:1px solid silver;
font-size:12px;}
.cb {display:none;}
.open {display:inline-block;}
<!-- HTML -->
<button>b1</button><span class="cb">content b1...</span>
<br />
<button>b2</button><span class="cb">content b2...</span>
<br />
<button>b3</button><span class="cb">content b3...</span>
jsFiddle: https://jsfiddle.net/ypofz4d5/55/

Categories

Resources