I have 6 'like' buttons, clicking on which, counter increase. How can i use event handler on all 'like' buttons. In my example only the last one is working.
constructor(model) {
this.count = 0;
for(let i = 0; i < 6; i++){
this.renderInitialTodoForm();
}
this.likeButton.addEventListener('click', () => {
this.count++;
this.likeCount.innerHTML = this.count;
})
}
renderInitialTodoForm = () => {
this.app = this.getElement('#root');
this.likeButton = this.createElement('span', 'likeImg');
this.likeButton.textContent = '👍';
this.likeCount = this.createElement('span', 'like');
this.likeCount.textContent = 0;
this.app.append( this.likeButton, this.likeCount);
};
You render 6 like buttons but only keep a reference to one - this.likeButton. It is set to the last button created.
I think you should add the event listener to each button inside the loop.
You can do that by either adding the code bloc to renderInitialTodoForm or directly inside the for loop.
constructor(model) {
for(let i = 0; i < 6; i++){
this.renderInitialTodoForm();
}
}
renderInitialTodoForm = () => {
this.count = 0;
this.app = this.getElement('#root');
this.likeButton = this.createElement('span', 'likeImg');
this.likeButton.textContent = '👍';
this.likeButton.addEventListener('click', () => {
this.count++;
this.likeCount.innerHTML = this.count;
})
this.likeCount = this.createElement('span', 'like');
this.likeCount.textContent = 0;
this.app.append( this.likeButton, this.likeCount);
};
Does this work for you?
Related
I've been testing around to see if you can prevent having duplicate event listeners
The code below loops through all the buttons with a certain attribute.
the problem is it only works with ONE button
let LOGIC;
let removeListener = undefined;
let test = document.getElementById("test")
let allButtons = document.querySelectorAll("input[btn]")
function GameLogic(btn, test) {
test.innerHTML = eval(`${test.textContent} + 1`)
btn.value += "1"
}
let Apply = function() {
for (let i = 0; i < allButtons.length; i++) {
if (removeListener == true){
allButtons[i].removeEventListener("click", LOGIC)
}
LOGIC = GameLogic.bind(null, allButtons[i], test)
allButtons[i].addEventListener("click", LOGIC);
removeListener = true
}
}
document.getElementById("redo").addEventListener("click", Apply)
Here is the HTML:
<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<button id = "redo"> Redo Function </button>
<p id = "test">0</p>
I've tried so many different solutions and nothing really worked.
The logic seemed to add up the in the aforementioned code.
First of all, in your function Accept, the statement removeListener = true seems to be in the wrong place.
let Apply = function () {
for (let i = 0; i < allButtons.length; i++) {
if (removeListener == true) {
allButtons[i].removeEventListener("click", LOGIC)
}
LOGIC = GameLogic.bind(null, allButtons[i], test)
allButtons[i].addEventListener("click", LOGIC);
removeListener = true //Set as true for the first button
}
}
Instead of :
let Apply = function () {
for (let i = 0; i < allButtons.length; i++) {
if (removeListener == true) {
allButtons[i].removeEventListener("click", LOGIC)
}
LOGIC = GameLogic.bind(null, allButtons[i], test)
allButtons[i].addEventListener("click", LOGIC);
}
removeListener = true //Set as true after the first loop has run
}
Second issue is your variable LOGIC. As it is changed in every steps of the loop, when you click on Redo, you have the value for the last button instead of the first.
A solution could be to use an array like this :
let LOGICS = []; //Now is an array
let removeListener = undefined;
let test = document.getElementById("test")
let allButtons = document.querySelectorAll("input[btn]")
function GameLogic(btn, test) {
test.innerHTML = eval(`${test.textContent} + 1`)
btn.value += "1"
}
let Apply = function () {
for (let i = 0; i < allButtons.length; i++) {
if (removeListener == true) {
allButtons[i].removeEventListener("click", LOGICS[i])//So when your remove the event listener, it is the function you have used to add it who is passed
}
LOGICS[i] = GameLogic.bind(null, allButtons[i], test)
allButtons[i].addEventListener("click", LOGICS[i]);
}
removeListener = true
}
document.getElementById("redo").addEventListener("click", Apply)
The id attribute needs to be unique. You have multiple buttons with the same id ("DIE"). That's not allowed and makes the html invalid
I want to increase cart.amount on any event click but has work one time
should be a refresh to increase another one:
window.addEventListener("load", () => {
for (let i = 0; i < amount_btns_up.length; i++) {
amount_btns_up[i].addEventListener("click", function (e) {
id = e.target.dataset.amount;
amount_change_up(id);
});
}
});
function amount_change_up(id) {
mycart = JSON.parse(localStorage.getItem("myCart"));
for (let j = 0; j < mycart.length; j++) {
if (mycart[j].ISBN === id) {
mycart[j].amount++;
}
}
}
After incrementing the amount of the item, you'll need to save it back to Local Storage for the line
JSON.parse(localStorage.getItem("myCart"))
to parse the updated amount on subsequent clicks.
function amount_change_up(id) {
mycart = JSON.parse(localStorage.getItem("myCart"));
for (let j = 0; j < mycart.length; j++) {
if (mycart[j].ISBN === id) {
mycart[j].amount++;
}
}
localStorage.myCart = JSON.stringify(mycart);
}
You also might consider using the more semantically appropriate .find method.
function amount_change_up(id) {
mycart = JSON.parse(localStorage.getItem("myCart"));
mycart.find(item => item.ISBN === id).amount++;
localStorage.myCart = JSON.stringify(mycart);
}
Also, unless the mycart identifier is used elsewhere in your script, consider making it a local variable instead of a global one. Same for the ID.
function amount_change_up(id) {
const mycart = JSON.parse(localStorage.getItem("myCart"));
mycart.find(item => item.ISBN === id).amount++;
localStorage.myCart = JSON.stringify(mycart);
}
window.addEventListener("load", () => {
for (let i = 0; i < amount_btns_up.length; i++) {
amount_btns_up[i].addEventListener("click", function (e) {
amount_change_up(e.target.dataset.amount);
});
}
});
I'd also recommend using DOMContentLoaded instead of load so that the client doesn't have to wait for images to be fully downloaded for your JS to start working. Or, even better, use an external script with the defer attribute on the tag.
Please anyone can help to fix the issue with my code, sometimes I have to click twice to select the next elements
var varientbtn = document.getElementsByClassName('clickthisbtn');
for(let i = 0; i < varientbtn.length; i++) {
varientbtn[i].onclick = function () {
const rbs = document.querySelectorAll('input[name="choice"]');
let selectedValue;
let varientSelectedPrice;
for (const rb of rbs) {
if (rb.checked) {
selectedValue = rb.value;
varientSelectedPrice = rb.getAttribute("data-price");
break;
}
}
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
}
}
Live preview:
https://codepen.io/Elkazi/pen/wvJeErg
That's because when one of labels be clicked, the checked value of related radio still not change.
Try this
const rbs = document.querySelectorAll('input[name="choice"]');
for(let i = 0; i < rbs.length; i++) {
rbs[i].addEventListener('change', function () {
let selectedValue;
let varientSelectedPrice;
for (const rb of rbs) {
if (rb.checked) {
selectedValue = rb.value;
varientSelectedPrice = rb.getAttribute("data-price");
break;
}
}
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
});
}
rbs[0].dispatchEvent(new Event('change'));
Since you are adding event listener to the label element, you should make use of its for attribute to get the related input field. That way you don't have to run a loop for all inputs and will always get the latest/correct value.
this will point to the element on which the event handler is called.
var varientbtn = document.getElementsByClassName('clickthisbtn');
for(let i = 0; i < varientbtn.length; i++) {
varientbtn[i].onclick = function () {
let relatedInput = document.getElementById(this.getAttribute("for"));
let selectedValue = relatedInput.value;
let varientSelectedPrice = relatedInput.getAttribute("data-price");;
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
}
}
I am making a task planner using classes.
These tasks are saved in the form of dynamically appended cards.
I am adding three cards in the array in class CardManager.
When I am selecting a card to delete by pressing a delete button the id is retrieved correctly, but in the last delfunc function which has a for loop, I am getting wrong array length.
So splice is not working.
The problem is in the loop of last function called delfunc().
class Card {
constructor(id, cname, pic, description, assignee, dDate, st) {
this.id = id;
this.cname = cname;
this.pic = pic;
this.description = description;
this.assignee = assignee;
this.dDate = dDate;
this.st = st;
// this.info=info;
}
}
class CardManager {
constructor() {
this.cardArr = [];
this.currentId = 1;
}
addcard(cname, pic, description, assignee, dDate, st) {
const nCard = new Card(this.currentId++, cname, pic, description, assignee, dDate, st); //creates
an instance of class card
this.cardArr.push(nCard);
}
}
const cardDeck = new CardManager(); //create an instance of card manager to access the members
// cardDeck.addcard("laundry","test","testing","Saeed","thursday","to do");
let tname = document.querySelector("#text1"); //accepting user input from form
let tdes = document.querySelector("#des");
let assignee = document.querySelector("#assignee");
let dDate = document.querySelector("#dDate");
let sTatus = document.querySelector("#stAtus");
let addButton = document.querySelector("#addButton");
addButton.onclick = function () {
alert("here i am card deck");
cardDeck.addcard(tname.value, "test", tdes.value, assignee.value, dDate.value, sTatus.value);
$('#myModal').modal('hide');
}
let btn1 = document.querySelector("#btn1");
let buttonCount = 1;
btn1.onclick = function displayListHtml() {
let html = "";
alert(cardDeck.cardArr.length);
for (let i = 0; i < cardDeck.cardArr.length; i++) {
html = `<div class="card">
<h1>${cardDeck.cardArr[i].cname}</h1>
<img src="sample.jpg" alt="Denim Jeans" style="width:100%">
<p>${cardDeck.cardArr[i].description}</p>
<p>${cardDeck.cardArr[i].assignee}</p>
<p>${cardDeck.cardArr[i].dDate}</p>
<p>${cardDeck.cardArr[i].st}</p>
<p>${cardDeck.cardArr[i].id}</p>
<p><button class="delete btn btn-primary" id="dbutton_${cardDeck.cardArr[i].id}">
Delete</button></p>
<p><button class="Edit btn btn-primary" id="ebutton_${cardDeck.cardArr[i].id}">
Edit</button></p>
</div>`;
buttonCount++;
}
const taskcontainer = document.querySelector("#taskcontainer");
const element = document.createRange().createContextualFragment(html);
element.querySelector("button.delete")
.addEventListener("click", delfunc);
element.querySelector("button.Edit")
.addEventListener("click", edifunc);
// element.addEventListener("click",yourClickEventHandler);
taskcontainer.append(element);
}
function delfunc() {
alert("i am in delete function");
const taskElement = event.target.closest(".delete"); //see line 74.
let delIdArr = taskElement.id.split("_"); //spliting the id by underscore. i.e . dbuton_id
let retreiveId = delIdArr[1];
for (let j = 0; j < this.cardDeck.cardArr.length; j++) {
if (retreiveId === j) {
this.cardDeck.cardArr.splice(retreiveId, 1);
}
}
}
Here is minimal version your concern. But looks like splice call doing as expected.
const del = (cardArr, retreiveId) => {
for (let j = 0; j < cardArr.length; j++) {
if (retreiveId === j) {
cardArr.splice(retreiveId, 1);
}
}
};
const cardArr = [2, 3, 4];
// delete the index 1
del(cardArr, 1);
console.log(cardArr);
// Case where delete index out of array index
const a = [1];
del(a, 1)
console.log(a);
function delfunc() {
alert("I am in delete function");
const taskElement = event.target.closest(".delete");//see line 74.
let delIdArr = taskElement.id.split("_");
let retrieveId = delIdArr[1];
var arr=[];
for (let j = 1; j <= cardDeck.cardArr.length; j++ ) {
if (retrieveId == j) {
arr = cardDeck.cardArr.splice(retreiveId, 1);
}
I am trying to dynamically add onclick function to "li" tagged elements.
But the event does not fires.
Here is my code:
var arrSideNavButtons = [];
var sideNavLi = document.getElementsByClassName('side-nav')[0].getElementsByTagName('li');
var arrayOfSceneAudios = [scene1Audio, scene2Audio,...];
for (var i = 0; i < sideNavLi.length; i++) {
sideNavLi[i].onclick = function() {
arrayOfSceneAudios[i].play();
}
arrSideNavButtons.push(sideNavLi[i]);
}
Is it possible to code it this way?
If yes, what is my mistake?
Thanks a lot.
Wrap your onclick handler in a closure, else it only get assigned to the last elem in the loop:
for (var i = 0; i < sideNavLi.length; i++) {
(function(i) {
sideNavLi[i].onclick = function() {
arrayOfSceneAudios[i].play();
}
arrSideNavButtons.push(sideNavLi[i]);
})(i)
}
I think it's better to reuse one single function, instead of creating a new one at each iteration:
var arrSideNavButtons = [],
sideNavLi = document.getElementsByClassName('side-nav')[0].getElementsByTagName('li'),
arrayOfSceneAudios = [scene1Audio, scene2Audio,...],
handler = function() {
this.sceneAudio.play();
};
for (var i = 0; i < sideNavLi.length; i++) {
sideNavLi[i].sceneAudio = arrayOfSceneAudios[i];
sideNavLi[i].onclick = handler;
arrSideNavButtons.push(sideNavLi[i]);
}