Toggle Two Divs Onclick JavaScript - javascript

I am writing a function that toggles two divs onclick. I have 2 functions that displays an api json data as a table and graph (formatGraph and formatTable).
i have created two different divs and appended the formatGraph and formatTable functions to those divs. Then created a mainDiv to wrap the two divs.
I have an if statement that checks for when to show or hide the divs. I am calling the formatData function somewhere in my fetch call while rendering my result. I have a css file with the following code:
.displayTable {
display: block;
}
.displayGraph{
display: none;
}
But I am currently getting undefined and
Uncaught TypeError: Cannot read properties of null (reading 'style')
at HTMLButtonElement.
Any idea what I am missing, or how I can go about this? Here's my function:
const formatData = (response) => {
const mainDiv = document.createElement("div");
const div1= document.createElement("div");
div1.classList.add("displayTable");
div1.appendChild(formatTable(response));
mainDiv.appendChild(div1)
const div2 = document.createElement("div");
div2.classList.add("displayGraph");
div2.appendChild(formatGraph(response));
mainDiv.appendChild(div2)
viewTable.addEventListener("click", function() {
if(document.querySelector('.displayTable').style.display === "none") {
document.querySelector('.displayGraph').style.display = 'none';
document.querySelector('.displayTable').style.display = 'block';
}
else{
document.querySelector('.displayTable').style.display === "none"
document.querySelector('.displayGraph').style.display = 'block';
}
})
};

your code looks OK, but you're forgetting to append mainDiv to the document. That's why you're getting null as a result of calling document.querySelector(".displayTable") and document.querySelector(".displayGraph"). Using the access operator in null results in a TypeError.
//...
const div2 = document.createElement("div");
div2.classList.add("displayGraph");
div2.appendChild(formatGraph(response));
mainDiv.appendChild(div2)
document.body.appendChild(mainDiv);
//...
I've just used .appendChild in body, which appends the element at the end of the body. There are different methods that let you append elements at different locations of the DOM three. You could also create an empty element (has no children) in your HTML and use that element as a wrapper to append the DIVS.
Also, consider an improvement in your handler:
viewTable.addEventListener("click", function() {
// Execute document.querySelector once.
const displayTableDiv = document.querySelector('.displayTable')
const displayGraphDiv = document.querySelector('.displayGraph')
/* This new condition will prevent the Type Error if any. */
if (displayTableDiv && displayGraphDiv) {
if(displayTableDiv.style.display === "none") {
displayGraphDiv.style.display = 'none';
displayTableDiv.style.display = 'block';
}
else {
displayTableDiv.style.display === "none"
displayGraphDiv.style.display = 'block';
}
}
})

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>

Show a hidden DIV when jQuery runs (and hides another DIV) [duplicate]

This question already has answers here:
Show/hide 'div' using JavaScript
(15 answers)
Closed last month.
I've created a script that hides a DIV Class if it contains the text "No Event Found" or "Error". This part is working great, however when this happens I would like a hidden DIV ID to load in it's place. (#brxe-akqmjs)
<script>
const divs = document.getElementsByClassName('etn-not-found-post');
for (let x = 0; x < divs.length; x++) {
const div = divs[x];
const content = div.textContent.trim();
if (content == 'No Event Found' || content == 'Error') {
div.style.display = 'none';
}
}
</script>
How do I go about getting this to load correctly? The DIV I want to show is set to display:none.
Many thanks in advance.
I have tried adding if statements but this only results in the original code breaking.
You can simply using jquery hide() and show() method to hide and show the content. Here I rewrite the function in jquery format.
<script>
const divs = $('.etn-not-found-post');
for (let x = 0; x < divs.length; x++) {
const div = divs[x];
const content = div.textContent.trim();
if (content == 'No Event Found' || content == 'Error') {
div.hide();
}else{
div.show();
}
}
</script>
It depends on how that hidden DIV with ID been implemented.
Let me try to cover two approaches:
DIV is hidden with css using display: none;
DIV is hidden using attribute hidden
For both cases, first get the element reference by ID. For e.g.
var divWithID = document.getElementById("divWithID");
Now for case 1,update the style property.
dovWithId.style.display = "block";
For case 2, set the hidden attribute value to false
divWithID.setAttribute("hidden", false);
Hope this helps and clarifies your question.

Importing array of object from external file getting error: "function" is declared but its value is never read ts(6133)

I have array of objects
toDo.js
export const examples = [
{
question: "xx",
answer: "yy",
},
{
question: "xx",
answer: "yy",
},....]
Then i have following logic and then i import it to index.js. by this piece of code <div id="examples-container"></div> and then also i import it <script src="logic.js" type="module"></script>
I have following problem: Toggle (function) is declared but its value is never read ts(6133). I'm gettin this error when i click on buttons.
logic.js
import { examples } from "./Předměty/Matematika.js";
function toggle(i) {
const div = document.querySelector(`#result_${i}`);
if (div.style.display !== "none") {
div.style.display = "none";
} else {
div.style.display = "block";
}
}
let html = "";
examples.forEach((ex, i) => {
const example = `
<div class="card">
<div class="example">
${ex.question}
</div>
<button type="button" class="toggle" onclick="toggle(${i})">
Toggle
</button>
<div id="result_${i}" style="display:none" class="result">${ex.answer}</div>
</div>`;
html += example;
});
const container = document.querySelector("#examples-container");
container.innerHTML = html;
When i consol.log(examples). I get whole array. Also i've tried create new variable and then insert the array. Whole app worked how i expected when it was in one file but now i try to split it to different files because.. U know it's standart have app devided to more then 1 big file and also i have some future plans so it will be necessary. ^^
Best
Vojtěch
The problem is that the html code cannot access the toggle function. To fix this, you can build the DOM tree manually. So, instead of creating a string with html code in it and appending it onto the container element, you can create each element individually.
const container = document.querySelector("#examples-container");
examples.forEach((ex, i) => {
// Make the div for the <div class="card">
const card = document.createElement("div");
// Add the "card" class to the div
card.classList.add("card");
// Create the div for the <div class="example">${ex.question}</div>
const example = document.createElement("div");
// Add the "example" class
example.classList.add("example");
// Set the HTML inside of it to ex.question
example.innerHTML = ex.question;
// Add it to the card element
card.appendChild(example);
// Create the button for the <button class="Toggle">Toggle</button>
const button = document.createElement("button");
// Add the "toggle" class to the button
button.classList.add("toggle");
// Set the text inside of it to say "Toggle"
button.innerHTML = "Toggle";
// Add the onclick event listener
button.addEventListener("click", () => toggle(i));
// Add the toggle button to the card
card.appendChild(button);
// Create the div for the <div id="result_${i}" class="result">${ex.answer}</div>
const result = document.createElement("div");
// Add the id for the element
result.id = "result_" + i;
// Hide the result element (display: none)
result.style.display = "none";
// Add the "result" class
result.classList.add("result");
// Set it's HTML to the answer
result.innerHTML = ex.answer;
// Add the result element to the card
card.appendChild(result);
// Add the card to the container
container.appendChild(card);
});

Simplify code by applying property to multiple variables at once

I want to simplify this code
let a = document.querySelector(".arrow");
b = document.querySelector(".demo-desc1");
c = document.querySelector(".demo-title h3");
a.style.display = "none";
b.style.display = "none";
c.style.display = "none";
so I don't have to write style.display = "none" for every variable but rather to apply the propery for all variables at once.
Thank you.
If there's only one element of each in the DOM, put them all into a selector string, then iterate over the matching elements.
for (const elm of document.querySelectorAll('.arrow, .demo-desc1, .demo-title h3')) {
elm.style.display = 'none';
}
If there are multiple such elements, then you'll need
const selectors = ['.arrow', '.demo-desc1', '.demo-title h3'];
for (const s of selectors) {
document.querySelector(s).style.display = 'none';
}
But, in this sort of situation, an even better approach would be to toggle a class of a parent container, and have CSS rules that hide those elements when the class is on the parent container. I don't know what the rest of your HTML is like, but perhaps something like
<div class="demo-container">
<more HTML here>
</div>
.hide-children .arrow, .hide-children .demo-desc1, .hide-children .demo-title h3 {
display: none;
}
Then all you need is
document.querySelector('.demo-container').classList.add('hide-children');

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)";
}
}

Categories

Resources