0

I'm working on a todo list project from an Odin Project assignment (full stack development curriculum - www.theodinproject.com). I've used a composite design pattern that has worked fine so far. However, there's a HTML button I've not been able to add an event listener to. What's weird here is that there's another button I used similar code to create that works well. Now, the only difference between these to is an ìf statement that the first one is in.

So, this is the Container class

import Component from './component.js';

export default class Container extends Component{
  child;
  constructor(){
    super();
  }
  addChild(id, parentId){

    document.getElementById(parentId).appendChild(document.createElement('div')); 
    document.getElementById(parentId).lastChild.id = id;
    document.getElementById(parentId).lastChild.innerHTML = this.child.innerHTML;
    document.getElementById(parentId).lastChild.className = this.child.className;

    if(document.getElementById(id).className!='check-list'){
      document.getElementById(id).innerHTML+="<button id='"+id+"-add-button'>Add</button>";
      if(document.getElementById(id).lastChild){
        alert('Found');
      }
      document.getElementById(id).lastChild.addEventListener('click', (e)=>{
        e.stopPropagation();
        this.child.addChild(id);
      });
    }

    document.getElementById(id).innerHTML+="<button id='"+id+"-remove-button'>Delete</button>";

    document.getElementById(id+'-remove-button').addEventListener('click', ()=>{
    document.getElementById(parentId).removeChild(document.getElementById(id)); 
    });    

    let inputs = document.getElementById(parentId).getElementsByClassName('input');
    for(let i=0; i<inputs.length; ++i){ 
     inputs[i].addEventListener('input', ()=>{
       inputs[i].dataset.storage = inputs[i].value;});
    }
  }
}

In the following snippet I check that the button is found before assigning the event. Effectively the button is found.

if(document.getElementById(id).className!='check-list'){
      document.getElementById(id).innerHTML+="<button id='"+id+"-add-button'>Add</button>";
      if(document.getElementById(id).lastChild){
        alert('Found');
      }
      document.getElementById(id).lastChild.addEventListener('click', (e)=>{
        e.stopPropagation();
        this.child.addChild(id);
      });
    }

When I run the website the button is rendered and the alert is triggered. Although clicking on that button is useless. Now if we take a look at the following snippet we can see that it's no so much different to the first one and its button does trigger the expected function.

    document.getElementById(id).innerHTML+="<button id='"+id+"-remove-button'>Delete</button>";

    document.getElementById(id+'-remove-button').addEventListener('click', ()=>{
    document.getElementById(parentId).removeChild(document.getElementById(id)); 
    });    

By accident I changed

document.getElementById(id).lastChild.addEventListener('click', (e)=>{
        e.stopPropagation();
        this.child.addChild(id);
      });

for

document.getElementById(parent).lastChild.addEventListener('click', (e)=>{
        e.stopPropagation();
        this.child.addChild(id);
      });

Resulting in adding the event to all objects within the parent div including the button I'm talking about. Aside form this, I've tried to find out if there's a execution order problem or anything related to not finding the object but the object is definitely found. I've hard coded the id of the element like this document.querySelector(idoftheelement).lastChild.addEvenListener but console spits out a null error. Also checked these two questions: Add event listener to dynamically created button and Add event listener to future item (without jQuery) -> not good either

Can anyone lend me a hand with this please?

wavesinaroom
  • 105
  • 8
  • 1
    It's better to use `.classList.includes("check-list")`, in case the element has multiple classes. – Barmar Nov 02 '22 at 23:43
  • Where do you set `this.child`? – Barmar Nov 02 '22 at 23:45
  • 1
    Either your selector query is wrong or you're trying to query an element that does not exist yet. Make sure your JS is loaded after the html. Or check you've created the button in your script before you add your listener. – ngearing Nov 02 '22 at 23:45
  • @Barmar thanks for the reply. The conflicting button is created so `.classList.includes("check-list") makes no difference this time sorry. `this.child` is defined in the same class and it runs well if I try another button. – wavesinaroom Nov 03 '22 at 15:23
  • @ngearing thanks for the suggestion. I feel you can be right about this. if I run `document.getElementById(id).innerHTML+= ""` I can click on the button and get that alert whereas `document.getElementById(id).innerHTML += "; document.getElementById('mybutton').onclick=alert('works');` does not – wavesinaroom Nov 03 '22 at 15:43

1 Answers1

0

Based on @ngearing answered I moved the event creation code few lines down to make sure the button was created before assigning the event. So yeah Cheers ngearing!

import Component from './component.js';

export default class Container extends Component{
  child;
  constructor(){
    super();
  }
  addChild(id, parentId){

    document.getElementById(parentId).appendChild(document.createElement('div')); 
    document.getElementById(parentId).lastChild.id = id;
    document.getElementById(parentId).lastChild.innerHTML = this.child.innerHTML;
    document.getElementById(parentId).lastChild.className = this.child.className;

    if(!document.getElementById(id).classList.contains('check-list')){
      document.getElementById(id).innerHTML+="<button id='"+id+"-add-button'>Add</button>";
    }

    this.removeSelf(id);

    if(document.getElementById(id+'-add-button')){
      document.getElementById(id+'-add-button').addEventListener('click', (e)=>{
        alert(e.currentTarget);
        e.stopPropagation();
        this.child.addChild(id);
      });
    }

    let inputs = document.getElementById(parentId).getElementsByClassName('input');
    for(let i=0; i<inputs.length; ++i){ 
     inputs[i].addEventListener('input', ()=>{
       inputs[i].dataset.storage = inputs[i].value;});
    }
  }
}
wavesinaroom
  • 105
  • 8