I have a couple of buttons which I'm trying to loop through and add a event listener function to them. I do this by using the following code:
function handleButtonClick({
target
}) {
const btnNode = target.closest('button');
console.log('hi')
}
const btns = document.querySelectorAll('.answerBtn');
btns.forEach(btns => {
btns.addEventListener('click', handleButtonClick)
})
Everytime a button is clicked it should run the function and it does. The only problem is that if I have 4 buttons, it runs the first button 4 time, the 2th button 3 times, the 3th button 2 times and the last ones. I know this happens because of the loop, but is there a way to make sure that it doesn't matter on what button I press, it only runs the function once?
let clickCountStorage = new Map;
class Question {
/**
* @param {string} question
* @param {string} prefix
* @param {string} description
* @param {string} display
* @param {string} answerType
* @param {string} multiSelect
* @param {Answer[]} answers
*/
constructor(question = "", prefix = "", description = "", display = "", answerType = "", multiSelect = "",
answers = []) {
this.question = question;
this.prefix = prefix;
this.description = description;
this.display = display;
this.answerType = answerType;
this.multiSelect = multiSelect;
this.answers = answers;
}
}
class Answer {
constructor(id = "", name = "") {
this.id = id;
this.name = name;
}
}
function createButton(id) {
let generateNewAnswer = document.createElement('button');
generateNewAnswer.setAttribute('type', 'button');
generateNewAnswer.id = `answerBtn${ id }`;
generateNewAnswer.classList.add('answerBtn');
generateNewAnswer.innerHTML = 'Add Answer';
return generateNewAnswer
}
function main() {
function handleButtonClick() {
let target = event.target;
const btnNode = target.closest('button');
const buttonClickTotal = clickCountStorage.get(btnNode) 1;
clickCountStorage.set(btnNode, buttonClickTotal);
const clickCountList = Array
.from(
clickCountStorage.values()
);
const allButtonsClickTotal = clickCountList
.reduce((total, count) => total count, 0);
const AllBtnsClickedThreeTimes = clickCountList
.every(count => count >= 3);
console.log({
buttonClickTotal,
allButtonsClickTotal,
AllBtnsClickedThreeTimes,
});
}
const btns = document.querySelectorAll('.answerBtn');
console.log(btns)
btns.forEach((btn) => {
btn.addEventListener('click', handleButtonClick);
console.log(btn)
})
}
class Structure {
constructor() {
/**
* @type {Question[]}
*/
this.questions = [];
this.clickCount = 0;
this.currentQuestion = this.questions.length;
this.displayArr = ["Selecteer soort:", "button", "colorBtn", "position", "dropdown"];
this.typeArr = ["Selecteer type:", "max", "all"];
this.MultiArr = ["Multiselect:", "true", "false"];
}
AddQuestion() {
let currentQuestion = this.questions.length;
// The new created question which has to be added to the questions.
let newQuestion = new Question();
// Push the new question to the question list.
this.questions.push(newQuestion);
// The div generator for the answers
let answerDIV = document.createElement('div');
answerDIV.className = 'answerDIV' currentQuestion;
answerDIV.id = 'AnswerDivId' currentQuestion;
document.getElementsByClassName('create')[0].appendChild(answerDIV);
let generateNewAnswer = createButton(currentQuestion);
clickCountStorage.set(generateNewAnswer, 0)
generateNewAnswer.onclick = _ => this.AddAnswer(currentQuestion);
document.getElementsByClassName('create')[0].appendChild(generateNewAnswer);
}
/**
* @param {int} workingQuestionIndex
*/
AddAnswer(workingQuestionIndex) {
let workingQuestion = this.questions[workingQuestionIndex];
let newAnswerIndex = workingQuestion.answers.length;
let newAnswerId = 'id' newAnswerIndex;
// The new answer to insert.
let newAnswer = new Answer(newAnswerId);
// Add the new answer to the total answers.
workingQuestion.answers.push(newAnswer);
let idElement = document.createElement('input');
idElement.setAttribute('type', 'text');
idElement.name = "id";
idElement.id = newAnswerId;
idElement.classList.add('id', 'QuestionNumber' workingQuestionIndex);
idElement.placeholder = 'Add the ID of the answer';
idElement.addEventListener('input', function(_) {
newAnswer.id = this.value;
});
// Appends the answers to the AnswerDiv
document.getElementsByClassName('answerDIV' workingQuestionIndex)[0].appendChild(idElement);
}
}
class GenerateArray {
constructor() {
this.structure = new Structure();
}
generateQuestionPart() {
this.structure.AddQuestion();
}
}
let newQuestion = new Question();
let struc = new Structure();
NewArray = new GenerateArray();
document.querySelectorAll('.QPB')[0].addEventListener('click', () => {
main()
})
body {
margin: 0;
padding: 0;
}
.container {
height: 1000px;
width: 800px;
position: relative;
margin-top: 5px;
left: 50%;
-ms-transform: translate(-50%, 5%);
transform: translate(-50%, 5%);
}
.QPB {
position: relative;
float: left;
margin-left: 15px;
margin-top: 10px;
margin-bottom: 10px;
border: none;
border-radius: 0.25rem;
color: white;
font-size: 40px;
background-color: #ff5c01!important;
width: 50px;
height: 50px;
}
.question,
.prefix,
.description {
position: relative;
margin-right: 5px;
width: 95%;
height: 30px;
margin-bottom: 10px;
margin-left: 15px;
}
.SelClassD,
.SelClassT,
.SelClassM {
position: relative;
margin-right: 5px;
width: 20%;
height: 30px;
margin-bottom: 10px;
margin-left: 15px;
border: 2px solid #ced4da;
border-radius: 0.5rem;
}
.SelClassD:focus,
.SelClassT:focus,
.SelClassM:focus {
outline: none !important;
border: 4px solid rgb(135, 206, 250, 0.5);
border-radius: 0.5rem;
}
.question,
.description,
.prefix,
.id,
.name {
border: 2px solid #ced4da;
border-radius: 0.5rem;
}
.question:focus,
.description:focus,
.prefix:focus,
.id:focus,
.name:focus {
outline: none !important;
border: 4px solid rgb(135, 206, 250, 0.5);
border-radius: 0.5rem;
}
.id,
.name {
position: relative;
width: 90%;
height: 30px;
margin-bottom: 10px;
margin-left: 55px;
}
.answerBtn {
width: 100px;
height: 40px;
background-color: #ff5c01!important;
color: white;
border: none;
border-radius: 0.25rem;
margin-bottom: 50px;
margin-left: 15px;
}
.CreateArray {
width: 95%;
margin-left: 20px;
margin-bottom: 10px;
height: 40px;
background-color: #3db556!important;
color: white;
border: none;
border-radius: 0.25rem;
}
/* card */
.DONOT {
margin-left: 15px;
font-style: italic;
font-size: 24px;
}
.card-body-home {
border: 2px solid rgba(0, 0, 0, .125);
border-bottom: none;
border-radius: 3px 3px 0 0;
}
/* form card */
.form-card-DT {
max-width: 800px;
border: none!important;
height: 100%;
/* padding-bottom: 10px; */
}
.form-card-header {
border: none;
background-color: #ff5c01!important;
color: white;
font-weight: 500;
font-style: italic;
font-size: 24px;
padding-top: 10px;
padding-left: 15px;
border-radius: 0!important;
height: 35px;
}
.form-card-body {
border-radius: 0;
border: solid 1px #b5b5b5;
border-top: none;
}
<div style='width: 1000px;margin: auto;'>
<div class='card text-dark bg-light mb-3 form-card-DT'>
<div class='card-header form-card-header'>Creeër een vragenlijst:</div>
<div class='card-body form-card-body'>
<div >Gebruik het volgende teken niet ivm error: '</div>
<div >
<button id="QuestionPartBtn" type="button" onclick="NewArray.generateQuestionPart()">
</button>
<br><br>
</div>
<div >
<button id="download-btn" >Generate Code</button>
</div>
</div>
</div>
</div>
CodePudding user response:
const btns = document.querySelectorAll(".answerBtn");
btns.forEach(btn => {
btn.addEventListener("click", () => handleButtonClick(btn))
});
function handleButtonClick(btn){
if(btn.style.background !== 'red'){
btn.style.background = 'red'
}else{
btn.style.background = 'grey'
}
console.log(btn)
}
<button >0</button>
<button >1</button>
<button >2</button>
<button >3</button>
This should do the trick. Tested it on code pen.
CodePudding user response:
You can also try to use Event Bubbling and assign only one "click" event listener to the closest common parent