Trying to understand eventListeners within eventListeners

Hello all, i have a problem. It deals with an eventListener within an eventListner. The first eventListener dynamically generates html. The second one tries to move the html element. It successfully moves the generated html but if more than one html element is created then the eventListener fires twice. I am trying to thoroughly understand why. this is done. The code is below:

const createBtn = document.querySelector('button.createBtn');


createBtn.addEventListener('click', createTodo);

function createTodo(){
    let div = document.querySelector("#placement-div");
    let todo = document.querySelector('textarea');
    let newDiv = document.createElement('div');
    let moveBtn = document.createElement('button');

    if(todo.value === ""){
        alert("Invalid");
    } else{
        
        newDiv.classList = "bg-opacity-20 rounded-lg bg-gray-100 flex flex-col";
        moveBtn.classList = "w-4/12 border-black border rounded-full moveBtn";
        moveBtn.innerText = "Move";
        newDiv.innerHTML = `
        <p class="p-3">${todo.value}</p>
        `;
        moveBtn.parentNode = newDiv;
        newDiv.parentNode = div;
    
        newDiv.appendChild(moveBtn);
        div.appendChild(newDiv);
        todo.value = "";
    }
    
    const moveBtns = document.querySelectorAll('.moveBtn');

    //TODO edit make sure the click eventhandler first click does not double click.
    //it does a double click
    moveBtns.forEach((btn) => {
        btn.addEventListener('click', () => {
            
            moveProgress(btn);
        });
    })
    
}

function moveProgress(btn){
    console.log(btn.previousElementSibling);
    //gets the button that was created in the create todo method
    //is the parent div of btn
    let todo = btn.parentNode;
    //is the parent column of the todo
    let parent = todo.parentNode;
    if(todo.id === "last" ){
        let closeBtn = document.createElement('button');
        closeBtn.innerText = 'Close';
        todo = closeBtn.parentNode;
        todo.appendChild(closeBtn);
    }

    const todoDiv = document.querySelectorAll('.todo-div');
    
    let found;
    

    todoDiv.forEach((div, index) => {
        if(parent === div){
            found = index + 1;
        } 
        
    })
    todoDiv[found].appendChild(todo);
    
}

Thank you!

There can be multiple event listeners for the same event, and that’s what happening here. Function is adding another listener, regardless if it was added previously to the element.

1 Like

Yeah its like @sanity said. Every time you run the function function createTodo() , you grab all the existing buttons with const moveBtns = document.querySelectorAll('.moveBtn'); and then loop through them adding a new event listener btn.addEventListener('click', () => { ... }); and since you can have multiple listeners for the same event they just pile up.

1 Like

Okay so taking the moveBtns variable out of the function createTodo is what i should do?

I think what they are suggesting is that instead of looping through all the moveBtns just put the event on the moveBtn you created. That way you don’t register multiple listeners. Let me know if that helps.

Thank you

1 Like

I did do as you say but for this certain project it isnt what i need it too do also breaks other functions. I really do appreciate your input though!!!

Can you send a GitHub or codepen link with the full code. I can take a look at it and help you debug it.

Okay here is the github: GitHub - BacariH/Trello-Clone: made a trello clone to get me more organized

I did edit it so i could try another route with setting the attribute but it seems to be a dead end as well.

So I just submitted a pull request to your repo. The solution that I came up with was putting an event listener on the main element and then only responding to events where the target has a moveBtn class. This was a tough problem; I have run into the same thing countless times. Let me know if this what you are looking for, and good luck!

PR

Code

How did you come to the conclusion that you did? I was at a lost for a while…

I learned it from a course I was taking. I remember that the instructor was creating elements and then listening to the parent container. I realized that you were trying to do the same thing. I think it’s a common pattern for these situations. Just another thing to put in your tool chest.