javascript - get element that was clicked from collection of items - javascript

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.

Related

Accessing child elements in Javascript array via onclick (for loop)

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

Javascript created button, get id of the button pressed with onclick(

Note: this is my first project, sorry if this is obvious, I've looked everywhere and can't find it
I'm working on a website that would serve as a better UI then file explorer/VLC, so I've made a button where you can upload all your video files. With those file, my Javascript has a for loop to create a button for each individual video found in that directory, then it puts the name of the file in the button. And all that works, now what I'm struggling with is creating an onclick event that gets the ID of the button that was pressed. I'm really struggling on doing this so any help would be appreciated.
My javascript:
var animepaths = [];
var animenames = [];
//FILE UPLOADING
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
filesLoop(fileList)
});
//loops through every file found in the directory
//and saves the path and file name to local storage
function filesLoop(files){
for(var x = 0; x < files.length; x++){
animepaths.push(files[x].webkitRelativePath)
animenames.push(files[x].name)
}
printOnScreen(animenames, animepaths)
}
//Creating a button with an H2 tag inside
//Then display it on screen in the container (display grid)
function printOnScreen(animenames, animepaths){
for(var x = 0; x < animenames.length; x++){
const elem = document.createElement('button');
elem.classList.add("grid-item");
const elemtext = document.createElement('h2')
elemtext.innerHTML = animenames[x]
elemtext.classList.add("grid-innertext")
elem.appendChild(elemtext)
document.getElementById('container').appendChild(elem);
}
}
If you have more than 1 button you should identify the group of buttons via a class not an id.
in your case it's even easier, as you create the button pro grammatically, so we could create the event there ...
//your function and some of my code
function printOnScreen(animenames, animepaths){
for(var x = 0; x < animenames.length; x++){
createAndAppendButton(animenames[x], animepaths[i]);
}
}
function createAndAppedButton(name, path) {
let button = document.createElement('button');
button.classList.add("grid-item");
button.innerText = name
document.getElementById('container').appendChild(button);
button.addEventListener("click", function() {
//do something with the path, which is accessible her
console.log(path)
});
}
As you can see I removed your h1, as H1 cannot be a child of the button-tag
In any DOM event handler, the element that triggered the event is available within the handler via the this keyword. Therefore, to get the id of the button that triggered the event, you'd just use: this.id.
Here's an example:
document.querySelector("button").addEventListener("click", function(){
console.log("The button's id is: " + this.id);
});
<button id="btn">Click Me</button>
Maybe you can use something like:
function onClick(animenameId) {
...
// your magic here
...
}
function printOnScreen(animenames, animepaths){
...
elem.onclick = onClick(animenames[x]);
...
}
What do you think?

Toggle is-visible Class to Div Next to Trigger Element (Plain JS)

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

How to call unique function for dynamically created checkboxes in a div

I am trying to dynamically create a set of check-boxes that each call a function differently when clicked
function initAllButtons(variable, length)
{
for(c = 0; c < length; c++)
{
clicks.push(true);
}
for(i = 0; i < length; ++i)
{
var label = document.createElement("label");
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = true;
checkbox.value = btns[i];
checkbox.class = "colorCoder";
label.appendChild(checkbox);
document.getElementById('Buttons').appendChild(checkbox);
$('#Buttons').on('click', function(){updateData(i,clicks);});
}
}
Btns is just an array of strings. I really want to call the UpdateData function (which I have tested and works like it should) with the value or index of the button pressed, but nothing seems to be working.
This version just calls updateData ten times with index = 10. It obviously is not looking at the buttons as individual things. What am I doing wrong?
When dynamically adding elements to the dom, attaching event listeners gets tricky. This is a perfect use case for delegate on a parent container:
var clickcontainer = document.getElementById('clickcontainer');
clickcontainer.addEventListener('click', function(e) {
var target = e.target || e.srcElement;
e.stopPropagation();
}, false);
Use closures to get this behavior, the closure function will create a new isolated scope and store the state of the variables.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
function clickClosure(i, clicks){
return function(){
updateData(i,clicks);
}
}
function initAllButtons(variable, length)
{
for(c = 0; c < length; c++)
{
clicks.push(true);
}
for(i = 0; i < length; ++i)
{
var label = document.createElement("label");
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = true;
checkbox.value = btns[i];
checkbox.class = "colorCoder";
label.appendChild(checkbox);
document.getElementById('Buttons').appendChild(checkbox);
var clickFnct = clickClosure(i, clicks);
$('#Buttons').on('click', clickFnct);
}
}
The problem is that you are doing nothing in your click handler to reference the clicked element. To do that you need to specify selector as parameter to on(). That might look like this:
$('#Buttons').on('click', ':checkbox', function() {
// determine index of clicked item
var index = $('#Buttons :checkbox').index(this);
// call your function
updateData(index,clicks);
}
You should also place this code after your loop as you only need to execute this line of code once.
Guessing by the code you are actually attaching a click event on a button rather than on the checkbox itself. Once you've created the element with document.createElement you can create your jQuery object and use the event handlers jQuery got.
var checkbox = document.createElement("input");
$(checkbox).on('click' function(){
//Code here
}
If you want to keep the value of i you must use a closure. Look at my fiddle:
http://jsfiddle.net/u13Le70g/

Can you use "this" attribute on onclick of an HTML tag?

Can you use the this tag for the onclick on an HTML tag?
Here's my JS code...
function changeImage() {
this/*<-- right there <--*/.src=a;
}
document.getElementsByTagName('img').onclick = function(){
changeImage();
} ;
Am I doing something wrong?
Use it this way...
function changeImage(curr) {
console.log(curr.src);
}
document.getElementsByTagName('img').onclick = function(){
changeImage(this);
} ;
You could use the .call() method to invoke the function with the context of this.
In this case, you would use:
changeImage.call(this)
Example Here
function changeImage() {
this.src = 'http://placehold.it/200/f00';
}
document.getElementsByTagName('img')[0].onclick = function(){
changeImage.call(this);
};
As a side note, getElementsByTagName returns a live HTMLCollection of elements. You need to apply the onclick handler to an element within that collection.
If you want to apply the event listener to the collection of elements, you iterate through them and add event listeners like this:
Updated Example
function changeImage() {
this.src = 'http://placehold.it/200/f00';
}
Array.prototype.forEach.call(document.getElementsByTagName('img'), function(el, i) {
el.addEventListener('click', changeImage);
});
Or you could simplify it:
Example Here
Array.prototype.forEach.call(document.getElementsByTagName('img'), function(el, i) {
el.addEventListener('click', function () {
this.src = 'http://placehold.it/200/f00';
});
});
You are doing two things wrong.
You are assigning the event handler to a NodeList instead of to an element (or set of elements)
You are calling changeImage without any context (so this will be undefined or window depending on if you are in strict mode or now).
A fixed version would look like this:
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].onclick = function () {
changeImage.call(this);
};
}
But a tidier version would skip the anonymous function that does nothing except call another function:
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].onclick = changeImage;
}
And modern code would use addEventListener.
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].addEventListener('click', changeImage);
}
However, images are not interactive controls. You can't (by default) focus them, so this approach would make them inaccessible to people who didn't use a pointing device. Better to use controls that are designed for interaction in the first place.
Generally, this should be a plain button. You can use CSS to remove the default padding / border / background.
If you can't put a button in your plain HTML, you can add it with JS.
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
var image = images[i];
var button = document.createElement('button');
button.type = "button";
image.parentNode.replaceChild(button, image);
button.appendChild(image);
button.addEventListener('click', changeImage);
}
function changeImage(event) {
this.firstChild.src = a;
}

Categories