So, I want to show some details when I click the details button. I have used for loop to loop through the buttons but it makes it so that when I click a single button, rest of the buttons get clicked as well. I understand it happens because of the for loop. But how do I make all the buttons clickable using a loop but prevent all of them from getting clicked when I click one?
I'm super new to JavaScript.
function showDetails() {
for (let i = 0; i < allProducts.length; i++) {
const getHiddenDescription = document.getElementsByClassName("details");
getHiddenDescription[i].style = "display: block";
console.log("clicked");
}
}
const getDetails = document.querySelectorAll(".btn-details");
for (let i = 0; i < allProducts.length; i++) {
getDetails[i].addEventListener("click", showDetails);
}
You can select the button which triggered the event listener by using an optional parameter available in the event listener callback, often named event, like so.
function showDetails(event) {
clickedButton = event.currentTarget;
clickedbutton.style = "display: block";
}
Related
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?
My CodePen
So when I click the delete and complete buttons it runs these functions
function deleteListItem(){
alert("Item was deleted");
}
function completeListItem(){
alert("This item was completed");
}
for both buttons. I want to know how I can use event delegation to separate these functions, that way whenever I click the complete button it isn't running both functions.
In your javascript, when you declare deleteButton and completeButton they are both assigned the same element, the ul. That element contains the entire list. That is not what you want, you want to handle clicks on the buttons. deleteButton should be assigned to your delete button element and your completeButton to your complete button element. To do this, simply use the ID of the buttons you want instead of the ID of the UL.
In you code, change this:
var deleteButton = document.getElementById("todo");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("todo");
completeButton.addEventListener("click", completeListItem);
To this:
var deleteButton = document.getElementById("Remove");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("Complete");
completeButton.addEventListener("click", completeListItem);
EDIT:
Since your buttons are not unique you should not use an id to add the event listener. You should use a class and assign the event listener to all the elements with the class by looping threw them. In your html add a class attribute to your buttons like this: <button class="Remove"><i class="fa fa-trash" aria-hidden="true"></i></button>. Then handle the events this way:
var deleteButtons = document.getElementsByClassName("Remove");
for (var i = 0; i < deleteButtons.length; i++) {
deleteButtons[i].addEventListener('click', deleteListItem, false);
}
var completeButton = document.getElementsByClassName("Complete");
for (var i = 0; i < completeButton.length; i++) {
completeButton[i].addEventListener('click', completeListItem, false);
}
var deleteButton = document.getElementById("Remove");
deleteButton.addEventListener("click", deleteListItem);
var completeButton = document.getElementById("Complete");
completeButton.addEventListener("click", completeListItem);
Assign addEventListener to specific id of the button. id todo is the ul so clicking anything inside ul will run both functions
Problem: Can't assign a double-click event handler to my generated inputs; is this feasible using the getElementsByTagName?
Thanks for any help
Here is the code:
Generated inputs
function list_tasks() {
let container = document.getElementById("todo");
container.innerHTML = ""
if (task_array.length > 0) {
for (let i = 0; i < task_array.length; i++) {
let input = document.createElement("input");
input.value = task_array[i];
input.classList.add("record");
input.disabled = true;
container.appendChild(input);
}
}
}
Attaching the event
document.getElementsByClassName("record").addEventListener("dblclick", editTask);
And the console.log is never called
function editTask(e){
console.log("double click")
}
Update
Trying to loop across the array, but still, no double click event is fired
let record = document.getElementsByClassName("record");
for(var i = 0; i <= record.length; i++){
document.getElementsByClassName("record")[i].addEventListener("dblclick", editTask);
}
getElementsByClassName returns a nodes list i.e. an array. To access the element you need to get the value form the array.
Try this:
document.getElementsByClassName("record")[0].addEventListener("dblclick", editTask);
This should work.
The reason why this doesn't work is because you are marking the inputs as disabled. Disabled inputs don't react to some events, and looks like double-click is one of them.
Also, as #Royson wrote, getElementsByClassName() returns a list of multiple elements. If you want to add an event listener to all of them you have 2 options:
The best one IMO, if possible, is to attach it while creating the elements in list_tasks() function:
let input = document.createElement("input");
input.value = task_array[i];
input.classList.add("record");
input.disabled = true;
input.addEventListener("dblclick", editTask); // <--- here
container.appendChild(input);
If this is not possible to due scopes being inaccessible, you just loop over the result of getElementsByClassName():
Array.from(document.getElementsByClassName("record")).forEach(el => el.addEventListener("dblclick", editTask));
Edit: The spec says that "click" events should be disabled on a disabled input. Event though double-click isn't specified directly, my guess is that it's implied by it being a click too, or it requires click to be enabled so it can catch two fast ones.
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls%3A-the-disabled-attribute
The way to do it is to create items as list items and then make contentEditable on the list items on double click B-)
Using this script to open 1 of multiple menus based on the target ID. The class is .dropdownDiv. The script starts by removing the "show" class from any .dropdownDiv's, then allowing the user to toggle the targeted .dropdownDiv.
The issue is, the .remove and .toggle don't appear to work together. They work individually just fine. I can toggle one div show-unshow all day long, but clicking the other buttons will not control it. I can do the reverse and have one button remove the div from another, but then the targeting button will not remove it's own div.
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function(event) {
var divs = document.querySelectorAll('.navButton');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', showDropDown);
}
});
function showDropDown() {
//un-show all dropdowns
var containers = document.querySelectorAll('.dropdownDiv');
for (var i = 0; i < containers.length; i++) {
containers[i].classList.remove('show');
}
// show targeted dropdown only
var d = document.getElementById(event.target.dataset.target);
d.classList.toggle("show");
console.log(d);
}
</script>
a trivial way to toggle something, that is using a flag and flip it each time you hit an action, so you can do something like so:
if(a)
{//something to do}
else
{// another action to do}
a = ! a;
so, you can remove the clicked drop down instead of removing all drop down classes.
This is a simple but intersting issue. Suppose I have two sections of respective class .toggle0 and .toggle1, suppose I want to display .toggle0 and hide .toggle1 when clicking on some tag .footer0, and vice-versa : I want to display .toggle1 and hide .toggle0 when clicking on some tag .footer1. Now this code works correctly
$('.toggle1').hide();
var i=0;
$(".footer"+i+"").click(function(){
$(".toggle"+(i+1) %2+"").hide();
$(".toggle"+i+"").show();
});
var j=1;
$(".footer"+j+"").click(function(){
$(".toggle"+(j+1) %2+"").hide();
$(".toggle"+j+"").show();
});
but this doesn't work in the sense that nothing happens on click event
for(var i=0;i<2;i++){
$(".footer"+i+"").click(function(){
$(".toggle"+(i+1) %2+"").hide();
$(".toggle"+i+"").show();
});
}
if I put this
$('.toggle1').hide();
var i=0;
$(".footer"+i+"").click(function(){
$(".toggle"+(i+1) %2+"").hide();
$(".toggle"+i+"").show();
});
i =1;
$(".footer"+i+"").click(function(){
$(".toggle"+(i+1) %2+"").hide();
$(".toggle"+i+"").show();
});
.toggle1 displays and .toggle0 hides when clicking on some tag .footer1 but .toggle0 does not display and .toggle1 does not hide when clicking on some tag .footer0 . It seems that the second click event takes precedence upon the first
The i within the the click handler isn't evaluated until a click, at which point the value has changed from when the handler was bound. If you want to go this route, you need to create a closure. Here's one method to do so:
for (var i = 0; i < 2; i++) {
$(".footer" + i + "").click(function () {
var idx = i;
return function () {
$(".toggle"+(idx+1) %2+"").hide();
$(".toggle"+idx+"").show();
console.log(idx);
}
}());
}
$('.footer0').click(function(){
$('.toggle0 .toggle1').hide();
$('.toggle0').show();
});
$('.footer1').click(function(){
$('.toggle0 .toggle1').hide();
$('.toggle1').show();
});