document.getElementById issues with for loop - javascript

My code fetches data from the backend API
for (var i = 0; i < myObj.length; i++) {}
stored object i want to display in variables and im able to display them accordingly
everything is fine until here
but I want to display the description in a popup
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_popup
based on this tutorial I have implemented the same
html1 += ` <div class="popup" onclick="myFunction()">Click me to toggle the popup!
<span class="popuptext" id="myPopup">${desc}</span>
</div>
<p > ${desc}</p>
<script>
function myFunction() {
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
}</script>
`;
but when I clicked on it I expected different cards to show different data accordingly but instead, it's just showing the data of the first card element
when clicked on the second one only the first card element pops up with only that particular data of that card
I thought the issue could be because of ID so gave dynamic variables as id
but it's of no use When clicked nothing is coming up
not even error
is there any way where we can display dynamic data based upon the card in that popup

IDs must be unique
Use the loop number to make a unique call to the function, and give each span its own ID.
html1 += ` <div class="popup" onclick="myFunction('${i}')">Click me to toggle the popup!
<span class="popuptext" id="myPopup-${i}">${desc}</span>
</div>
<p > ${desc}</p>
and you only need one script block for all of them
<script>
function myFunction(id) {
var popup = document.getElementById("myPopup-"+id);
popup.classList.toggle("show");
}</script>

I think it's because you are reusing the same id. In html element IDs have to be unique. You could try to append a sequence number to id="myPopup" as you loop, e.g. id="myPopup1", id="myPopup2" etc...

The problem is because you are using the id property. For that reason the first object works and the others no, Javascript takes the id an use it for the first that find and it discart the others.
Try giving the action by class to every button. Something like this:
const buttons = [...document.querySelectorAll('.btn-toggle')]
buttons.forEach(button => button.addEventListener('click', e => click(e)))
const click = e => e.target.parentElement.children[1].classList.toggle('show')
.show {
color: red;
display: block!important;
}
.hide{
display: none
}
<div>
Hello from div 1
<button class="btn-toggle">Toggle</button>
<div class="hide">Toggle!</div>
</div>
<div>
Hello from div 2
<button class="btn-toggle">Toggle</button>
<div class="hide">Toggle!</div>
</div>
<div>
Hello from div 3
<button class="btn-toggle">Toggle</button>
<div class="hide">Toggle!</div>
</div>

As everyone wrote, id is to be unique to work properly.
If you change your css to react to .popup.show it would become more simple:
//REM: this = div.popup
function myFunction(div){
div.classList.toggle('show');
}
.popup span{
display: none
}
.popup.show span{
display: block
}
<div class = 'popup' onclick = 'myFunction(this)'>click<span>clicked</span></div>

Related

Toggle re-hides all divs; need parent div to remain visible

Apologies in advance, I'm not terribly familiar with Javascript, but I do understand what this code is doing and why it is causing me this problem. I'm just not sure how to go about solving it AT all.
On my webpage I have an open/close dialogue toggle which is the parent div, the dialogue box is hidden upon the page loading. Within this dialogue box are more hidden divs for the dialogue options. Problem is, when one of the dialogue options is clicked, the script hides the entire dialogue box, preventing any of the dialogue options from being seen, because it can only show one div at a time, regardless of its parent or child status. When a div is clicked, all other divs are re-hidden.
I need the parent div to remain visible until the dialogue box toggle is clicked again. The individual choices DO need to hide/unhide when another choice is clicked.
Not sure if I should include any CSS here, it's just styling the dialogue box and its buttons within.
<div id="dialogue" style="display:none;">
<div class="room">
Room description here. What do you do?
<div class="buttons">
Pet the cat.
<br>
<div id="cat" style="display:none;">aw yeah kitty time</div>
Turn on the radio.
<br>
<div id="radio" style="display:none;">
<br>
audio file and tracklist here
</div>
</div>
</div>
</div>
<span class="toggle">
[Open/close dialogue.]
</span>
<script type="text/javascript">
var divs = ["cat", "radio", "dialogue"];
var visibleDivId = null;
function divVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
I probably need a third function here because currently all the toggles are grouped together, hence why they're interacting like this, but I don't have the first clue how to accomplish this. I have been looking and haven't found anything that seems to match my needs.
Made a few corrections to your HTML so the href does not refresh the page on click. Also added in a few attributes (aria-controls) to track which div the button controls. I added comments to the JavaScript. There are plenty of Aria attributes they typically help with accessibility but they are super useful for keeping track of things in HTML and passing information to JavaScript.
//create a function to handle the click that takes in the event as a argument
function handleClick(event) {
//find out which div the button controls
const ariaControls = event.currentTarget.getAttribute("aria-controls"),
//select the controlled div
controlledAria = document.getElementById(ariaControls);
// if the controlled div is cat
if (ariaControls === "cat") {
// hide the radio div
document.getElementById("radio").classList.add("hide");
// if the controlled div is radio
} else if (ariaControls === "radio") {
// hide the car div
document.getElementById("cat").classList.add("hide");
}
//toggle the hide div on the controlled div
controlledAria.classList.toggle("hide");
}
//select all the buttons
const buttons = document.querySelectorAll("button");
//for each button add an event listener when the button is clicked run the handle click function
buttons.forEach(button => button.addEventListener("click", handleClick))
.hide {
display: none;
}
<div id="dialogue" class="hide">
<div class="room">
Room description here. What do you do?
<div class="buttons">
<button aria-controls="cat">Pet the cat.</button><br>
<div id="cat" class="hide">aw yeah kitty time</div>
<button aria-controls="radio">Turn on the radio.</button><br>
<div id="radio" class="hide">audio file and tracklist here
</div>
</div>
</div>
</div>
<span class="toggle"><button aria-controls="dialogue">[Open/close dialogue.]</button></span>

hide / show div with a button not in the same div

I'm using elementor for my wordpress site and I wish to have a button in a first div (section) that control if a second and separate div (section) is display or not. I've tried to use the checkbox hack but it's working only if the checkbox is in the div as the content https://css-tricks.com/the-checkbox-hack/
Is there a solution to use CSS or even javascript ? If you advice to me to use javascript I'll put in my function.php file and as I'm begginer in javascript can you please write all the function I have to implement into my function.php file.
Basically it means :
<div>button</div> <div>content to show and hide on click on the button</div>
Best regards,
Clément
You can use Jquery:
1-Put an id to your DIV
<div id = "btn_show"> button </div> <div id = "show"> content to show and hide on click on the button </div>
2-Call jquery to display it
$("#btn_show").click(function(){
$("#show").show();
//or
$("#show").hide();
});
And jquery you can call it with CDN
<script src="https://code.jquery.com/jquery-3.6.0.js"</script>
In javascript without any library this could be very easy but you need to put an id on your divand your button.
<div id="myButton">button</div>
<div id="myDiv">
content to show and hide on click on the button
</div>
Then you just add a script section like this : (it just need to be after your div and your button in the DOM)
<script>
var myDiv = document.getElementById('myDiv');
var myButton = document.getElementById('myButton');
myButton.addEventListener('click', e => {
myDiv.classList.toggle('visible'):
});
</script>
And at last, you need a css like this:
.visible {
display: none;
}
Thanks for all of yours answers! Here what I use:
<button onclick="myFunctionopenclose()">Click Me</button>
<div id="myDiv" style="display:none;">content to hide and show</div>
<script> function myFunctionopenclose() {
var x = document.getElementById("myDiv");
if (x.style.display === "block") {
x.style.display = "none"; }
else {
x.style.display = "block";}}
Best regards,
Clément

remove only the div inside the parent div

In this websites the user can add as much boxes as he wants, and every box contains a green and blue small boxes, the user should be able to click the blue box to remove the green box. the issue is that every time I click the blue box it doesn't remove the green box unless there is only one parent box is made. I have tried a lot of ways but nothing is working.
let count = 0;
function addBox() {
let box = `
<div class="box">
<div class="lbox" id="lbox">
</div>
<div class="rbox" id="rbox">
</div>
<h1>
${count}
</h1>
</div>
`
$(`#boxes`).append(box);
document.getElementById("lbox").addEventListener("click", function() {
rbox.remove();
})
count++;
}
If you have more than one parent box you need to iterate over each one.
You need to do something like;
let boxes = document.querySelectorAll('.box');
boxes.forEach(function(box){
box.querySelector('lbox').addEventListener('click',function(){
box.remove();
});
})
I haven't tested this, but the key part is the forEach function. This means everything you do inside the function is scoped to that box.
id must, at all times, be unique per-document. Learn about this very basic here: https://www.w3schools.com/hTML/html_id.asp. Your code keeps readding the same id values over and over, making your HTML invalid and your code dysfunctional.
Here's a working code example that doesn't rely on ids to get the job done:
let count = 0;
function addBox() {
let box = document.createElement('div');
box.className = 'box';
box.innerHTML = `
<div class="lbox">
</div>
<div class="rbox">
</div>
<h1>
${count}
</h1>`;
document.getElementById('boxes').appendChild(box);
box.querySelector('.lbox').addEventListener('click', function() {
box.querySelector('.rbox').remove();
})
count++;
}
.lbox, .rbox {
display: inline-block;
height: 40px;
width: 40px;
}
.lbox { background-color: blue; }
.rbox { background-color: green; }
<button onclick="addBox()">Add Box</button>
<div id="boxes"></div>
you need to define to delete the other box inside the same parent div.
I would delete the id because the defenition in class is the same.
I would also change the class names to something, wich makes visible what the green and what the blue box is.
You can do following:
let count = 0;
function addBox() {
let box = `
<div class="box_wrapper">
<div class="blue_box">
</div>
<div class="green_box">
</div>
<h1>
${count}
</h1>
</div>
`
$(`#boxes`).append(box);
$( ".blue_box" ).click(function() {
$(this).parent().find(".green_box").remove();
});
count++;
}
I think document.getElementById will always select the first element only with the given id. Therefore only the first lbox element in the dom keeps getting more and more eventlisteners attached to it, while the others won't get any. Make the id's of your elements unique by appending the count. That will make sure that every element gets it's eventlistener:
let count = 0;
function addBox() {
let box = `
<div class="box">
<div class="lbox" id="lbox${count}">
</div>
<div class="rbox" id="rbox${count}">
</div>
<h1>
${count}
</h1>
</div>
`;
$(`#boxes`).append(box);
document.getElementById("lbox" + count).addEventListener("click", function() {
$(".rbox" + count).remove();
})
count++;
}

How to hide an element in if statement?

I am making an html change to a CMS that will affect all pages when the changes are live. I would like this html alert to only affect 1 specific page. I am attempting to do an if statement for the page title.
The logic is that if the page title is Test Article Two then show the html that I have put in place, if not then display=none. With this logic in place, I am viewing the html on all pages not just the one I want it to show.
<div class="container">
<div class="title-wrapper">
<span id="article-banner-country">#countryFullText</span> /
<span id="article-banner-category">#subCatText</span>
<div id="article-banner-title">#pageTitle</div>
<!--page alert -->
<div class="feedback-container content-desktop" id="alert-dialog">
<div class="feedback-left">
<p>Have any feedback? Reach out to us!</p>
</div>
<div class="feedback-right">
<button class="feedback-button">Give Feedback</button>
<button class="feedback-button">Dismiss</button>
</div>
</div>
</div>
</div>
<script>
function showAlert() {
if(#pageTitle === "Test Article Two") {
document.getElementById('alert-dialog').style.display = 'block';
}else {
document.getElementById('alert-dialog').style.display = 'none';
}
}
</script>
I'd recommend changing a class on the body element so that you can use CSS for the styling.
HTML: nothing really changed here
<body>
<div class="container">
<div class="title-wrapper">
<span id="article-banner-country">#countryFullText</span> /
<span id="article-banner-category">#subCatText</span>
<div id="article-banner-title">#pageTitle</div>
<div class="feedback-container content-desktop" id="alert-dialog">
<div class="feedback-left">
<p>Have any feedback? Reach out to us!</p>
</div>
<div class="feedback-right">
<button class="feedback-button">Give Feedback</button>
<button class="feedback-button">Dismiss</button>
</div>
</div>
</div>
</div>
</div>
</body>
javascript: just check the document.title and add the class the the body element
<script>
if(document.title === "Test Article Two") {
document.body.classList.add("show-alert");
}
</script>
Use CSS for the styling. Always hide #alert-dialog and only show it when we add the class to the body.
<style>
#alert-dialog {
display: none;
}
.show-alert #alert-dialog {
display: block;
}
</style>
If you are making static pages or using server side rendering, you could add logic to add a class to show or hide the alert element without adding more javascript to the page. It will have the relevant class(es) when the html is generated and delivered. This way you won't have to create a function, call it and manipulate the DOM after everything is rendered.
I may have missed this in the code above, are you calling the showAlert function anywhere? If not, your alert won't be shown (or will be shown depending on the default styles).
One thing I'd caution against is the imperative nature of the code here. If you wanted to reuse this alert functionality on another page, you'd have to add another more logic to detect another page title every time you wanted to use the alert. Since you are using a CMS, you might consider adding a flag to show the alert, and on this specific page, turn that flag on.
If you wanted to use the function strategy, I'd set your default alert styles:
#alert-dialog {
display: none;
}
.show {
display: block;
}
and try something like this:
<script>
function showAlert() {
if(document.title === "Test Article Two") {
document.getElementById('alert-dialog').classList.add('show');
}
}
document.addEventListener("DOMContentLoaded", showAlert);
</script>
Another alternative is to take a look at the path of the page this is supposed to be on (window.location.pathname) and using regex to see if it matches what you want. I'd recommend that over looking at the title since it's more likely the title of the page will change rather than the url.
In JavaScript, you can access the page title with document.title. You should change the script like this:
function showAlert() {
if(document.title === "Test Article Two") {
document.getElementById('alert-dialog').style.display = 'block';
} else {
document.getElementById('alert-dialog').style.display = 'none';
}
}

Javascript change div content upon a click

I'm pulling a content from PHP array and I have a situation like this:
<div class="weight-display">
<span>04/25/2011</span> <span>100lbs</span> <span>Edit</span> <a href="http://foo.com">Delete</span>
</div>
<div class="weight-display">
<span>04/27/2011</span> <span>150lbs</span> <span>Edit</span> <a href="http://foo.com">Delete</span>
</div>
etc...
Now when somebody clicks on Edit within, let's say, first div where weight is 100lbs, I just need that "div" to change and to have input field instead of simple text where weight is (while others will remain the same) and to be like this:
<div class="weight-display">
<span>04/25/2011</span> <input type="text" value="100" /> <span>Save</span> <span>Cancel</span>
</div>
<div class="weight-display">
<span>04/27/2011</span> <span>150lbs</span> <span>Edit</span> <a href="http://foo.com">Delete</span>
</div>
etc..
So basically div has to "reload itself" and change content. Now I really need some very simple Javascript solution. Preferably I would like a solution with a hidden div beneath original one, so they just swap places when user clicks on EDIT and in a case if CANCEL is pressed to swap places again so original div with text is displayed...
Thanks,
Peter
<style type="text/css">
/* Normal mode */
.weight-display div.edit {display:none}
/* Editor mode */
.weight-edit div.show {display:none}
</style>
<div class="weight-display">
<button onclick="toggle(this)">Edit this!</button>
<div class="edit"><input type="text" value="Test" /></div>
<div class="show">Test</div>
</div>
<script type="text/javascript">
function toggle(button)
{
// Change the button caption
button.innerHTML = button.innerHTML=='Edit this!' ? 'Cancel' : 'Edit this!';
// Change the parent div's CSS class
var div = button.parentNode;
div.className = div.className=='weight-display' ? 'weight-edit' : 'weight-display';
}
</script>
What you suggest is basically correct. I would generate two div's one for display and one edit. The edit div will initially have display: none. When the Edit is clicked, hide the display div and show the edit div.
How about something like:
onClick event calls a function (EDITED to be a little smarter than my original brute force method):
function swapdivs ( id_of_topdiv, id_of_bottomdiv ) {
var topdiv = getRefToDiv( id_of_topdiv );
var bottomdiv = getRefToDiv( id_of_bottomdiv );
var temp = topdiv.style.zIndex;
topdiv = bottomdiv.style.zIndex;
bottomdiv = temp.style.zIndex;
}
Could that or similar work for you? Or am I missing some subtle yet crucial requirement?

Categories