I am looping through an array like this:
<% thoughts.docs.forEach(function(thought, i) { %>
<div class="square-box-container">
<div class="pyp-image-container">
<div class="image-overlay">
By default, element class name 'image-overlay' is hidden with display: 'none'. I am trying to create a function with an onclick event, so when user clicks on div 'square-box-container', the image overlay for that element only changes to display: 'block'.
Currently I have the below code but I think my inner loop in wrong, as when I click on a square box container, the image overlays for ALL the square box containers change to display: 'block', as opposed to that container overlay only. Can anyone advise what I'm doing wrong please?
var containerItems = document.getElementsByClassName("square-box-container");
var overlayItems = document.getElementsByClassName("image-overlay");
for (var i = 0; i < containerItems.length; i ++) {
containerItems[i].onclick = function() {
for (var i = 0; i < overlayItems.length; i ++) {
overlayItems[i].style.display = 'block';
}
}
}
I'm not very familiar with use of child nodes, is that what is required here? Thanks
If you want only the associated element to have its display changed, don't loop inside the click handler - and use let instead of var.
for (let i = 0; i < containerItems.length; i++) {
containerItems[i].onclick = function () {
overlayItems[i].style.display = 'block';
}
}
Another option is to omit the overlayItems collection entirely, and navigate from the clicked element instead.
for (const container of document.getElementsByClassName("square-box-container")) {
container.addEventListener('click', (e) => {
e.currentTarget.querySelector('.image-overlay').style.display = 'block';
});
}
Related
Having this code:
let ev = document.querySelectorAll('.event p')
for (let i = 0; i < ev.length; i++) {
ev[i].addEventListener("click", function (e) {
// add this only for current clicked elem
e.currentTarget.src = './icon.png';
// And the rest of items should have this:
ev[i].src = './warning.png';
});
}
How can i change warning.png to all elements in this loop, but change src for element to have icon.png that was clicked? So kind of toggle. My code is not working as expected. Thanks.
You can reuse ev inside the event listener, like this: ev.forEach(evt => evt.src = './warning.png');
If the list of .event p changes, recalculate the list again, e.g. put ev = document.querySelectorAll('.event p') inside the listener.
let ev = document.querySelectorAll('.event p')
for (let i = 0; i < ev.length; i++) {
ev[i].addEventListener("click", function (e) {
// Change the icon for all items
ev.forEach(evt => evt.src = './warning.png');
// then change the icon for the current item
e.currentTarget.src = './icon.png';
});
}
In your code after the click event on element, that element's src is changing but later on it is changing again to ./warning.png. Rearranging them will solve the problem.
let ev = document.querySelectorAll('.event p');
const evLen = ev.length;
for (let i = 0; i < evLen; i++) {
ev[i].addEventListener("click", function (e) {
ev[i].src = './warning.png';
this.src = './icon.png';
});
}
The issue is that the statement ev[i].src = './warning.png'; within the for loop is overriding e.currentTarget.src = './icon.png'; . The solution here is changing all the elements within the for loop, and outside the loop change the icon ONLY for the targetted event.
let ev = document.querySelectorAll('button');
console.log(ev);
// Add event listener to each element
for (let i = 0; i < ev.length; i++) {
ev[i].addEventListener('click', (e) => {
for (let i = 0; i < ev.length; i++) {
// Change icon for all the elements
ev[i].src = './warning.png';
}
// Change icon only for targetted event
e.target.src = './icon.png';
});
}
Also, changed currentTarget to target since target is going to specifically get the element that triggered the event, whereas using currentTarget we can run into confusion in certain scenarios, because it will get the element that the event listener is attached to.
I have a working grid that show a cell for every title in the json:
async function loop_iteration(json, i, arr) {
arr.push(`<a onClick="show()" class="cell" id=${i}"><div >${json[i].title}</div> </a>`)
arr.push(`<div class="info" id=${i}>${json[i].title}<br><br><br><br><br>Game Size: ${json[i].size}<br><br>Last Update: ${json[i].date}</div>`)
}
I want to show on click of the class info.
The problem is that it gives always the same title(first), it's like is always the first cell to be clicked
I show the info div like this:
<script>
function showinfo() {
var node = document.querySelector('.cell.info')
var visibility = node.style.visibility;
node.style.visibility = visibility == "visible" ? 'hidden' : "visible"
}
</script>
while if i show the div using this:
function show(){
var divsToHide = document.getElementsByClassName("info");
for(var i = 0; i < divsToHide.length; i++)
{
divsToHide[i].style.visibility="visible";
}
//document.getElementsByClassName('info')['${i}'].style.visibility = 'visible';
}
happen something strange, the div showed is not the first but is like it show all the div
Thanks for any help.
I find out the problem.
It was the javascript, so i extract the id and then iterate the class with the id
function show(clicked_id){
clicked_id = parseFloat(clicked_id);
document.getElementsByClassName('info')[clicked_id].style.visibility = 'visible';
}
I need to use getElementsByClassName because I have several same buttons etc.
I work on a wordpress loop that displays a button for each new article, and a registration form must appear on each event when we click on the button.
When I click on the button, I want the form to be displayed and the button to be hidden.
Someone can help me ?
Sorry if there are mistakes, I am French.
var bouton = document.getElementsByClassName('btn_inscription');
var formulaire = document.getElementsByClassName('formulaire');
var MyFonction = function{
formulaire.style.display = 'block';
bouton.style.display ='none';
}
for (var i = 0; i < bouton.length; i++) {
bouton[i].addEventListener('click', MyFonction);
}
getElementsByClassName (along with .getElementsByTagName and .getElementsByName) return node list objects (array-like containers). You can't interact with individual element properties and methods on node lists, you have to work with objects within the container. To set up event handlers on all the elements in the node list, you can loop through the container and set the handler one at a time.
Now, getElementsByClassName returns a "live node list", which is one that re-scans the document every time you interact with it to ensure that your container has the most up to date set of matching elements. This can cause big drops in page performance and the need for live node lists is pretty uncommon. Instead, use the more modern .querySelectorAll(), which allows you to pass any valid CSS selector in and returns a static node list.
// Get all the desired elements into a node list
let elements = document.querySelectorAll(".test");
// Convert the node list into an Array so we can
// safely use Array methods with it
let elementsArray = Array.prototype.slice.call(elements);
// Loop over the array of elements
elementsArray.forEach(function(elem){
// Assign an event handler
elem.addEventListener("click", function(){
console.log("You clicked me!");
this.style.backgroundColor = "#ff0";
});
});
<div class="test">Something</div>
<div>Something</div>
<div class="test">Something</div>
<div>Something</div>
<div class="test">Something</div>
You need to use .bind(thisArg[, arg1[, arg2[, ...]]]) in order to pass the current index and element (rif. this):
var bouton = document.getElementsByClassName('btn_inscription');
var formulaire = document.getElementsByClassName('formulaire');
var MyFonction = function(idx, event) {
formulaire[idx].style.display = 'block';
this.style.display ='none';
}
for (var i = 0; i < bouton.length; i++) {
bouton[i].addEventListener('click', MyFonction.bind(bouton[i], i));
// ^^^^^^^^^^^^^^^^^^^
}
.formulaire {
display: none;
}
<button class="btn_inscription">1</button>
<button class="btn_inscription">2</button>
<button class="btn_inscription">3</button>
<div class="formulaire">1</div>
<div class="formulaire">2</div>
<div class="formulaire">3</div>
You need to make use of this inside your event handler:
var buttons = document.getElementsByClassName('btn_inscription');
var MyFunction = function() {
this.closest('.formulaire').style.display = 'block';
this.style.display ='none';
}
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', MyFunction.bind(buttons[i]));
}
This is supposed to be a very simple dropdown FAQ system, I know how to do this in jQuery but I want to learn plain JS.
I just want the individual clicked triggers to toggle the is-visible class to the content divs next to the clicked trigger. Like $(this).next addClass — just in JS.
I've really tried to search for this issue but 90% that shows up is how to do it in jQuery :-p
https://jsfiddle.net/48ea3ruz/
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
// access to individual triggers:
var trigger = allTriggers[i];
}
var allContent = document.querySelectorAll('.faq-content');
for (var i = 0; i < allContent.length; i++) {
// access to individual content divs:
var content = allContent[i];
}
// I don't know how to target the faq-content div next to the clicked faq-trigger
this.addEventListener('click', function() {
content.classList.toggle('is-visible');
});
Would really appreciate some advice! :-)
Use nextSibling, when you are iterating .faq-trigger
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
allTriggers[i].addEventListener('click', function() {
this.nextSibling.classList.toggle('is-visible');
});
}
nextSibling will also consider text-nodes, try nextElementSibling also
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
allTriggers[i].addEventListener('click', function() {
this.nextElementSibling.classList.toggle('is-visible');
});
}
Can someone show a way to show/hide a span using javascript
document.getElementById("test").style.display= 'visible';
document.getElementById("test").style.display= 'block';
In the HTML Code
<span id='test' ..
How can I overcome this problem. Is there any thing that I should think about?
UPDATE
I have a class like this one, I want to force mouse hovering on it.
<div id="test" class="tooltip effect">
<div id="second" href="#"> .. </div>
On css:
tooltip{..}
effect{..}
effect:hover{..}
Another option I tried besides your code is
document.getElementById("test").onmouseover = test.hover;
Should I re-write the hover class to another name-class, or should I tweak your code?
Use display none/default:
document.getElementById("test").style.display= 'none';
document.getElementById("test").style.display= '';
Below are some types and some easy to remember rules about them:
Default: the elements default property (generally block or inline)
Block: Generally on a line by itself. Has the width and height attributes (among other size/positioning attributes)
inline: on the same line as other elements/text. Does not have height/width attributes
Inherit: Inherits the parent element's display type
visible isn't a value for the display, you want none
I would do something like this to handle it:
function HideAndSeek(selector) {
var elements = undefined;
var displays = [];
if (!!selector.id) {
elements = [document.getElementById(selector.id)];
} else if (!!selector.class) {
elements = document.getElementsByClass(selector.class);
}
for (var elementIndex = 0; elementIndex < elements.length; elementIndex++) {
displays[elementIndex] = elements[elementIndex].style.display;
}
this.hide = function() {
for (var elementIndex = 0; elementIndex < elements.length; elementIndex++) {
elements[elementIndex].style.display = "none";
}
};
this.show = function() {
for (var elementIndex = 0; elementIndex < elements.length; elementIndex++) {
elements[elementIndex].style.display = displays[elementIndex];
}
};
}
This function can be used this way:
var hideAndSeek = new HideAndSeek({id: "test"});
and you can hide the element(s) by:
hideAndSeek.hide();
you can show them by:
hideAndSeek.show();
<span class="text-danger" id="spanAddressLine1" runat="server" style="display: none;"> //Here is your message </span>
JQuery code
For show:
$('#<%= spanAddressLine1.ClientID%>').show();
For hide:
$('#<%= spanAddressLine1.ClientID%>').hide();
Here spanAddressLine1 is the id of span