3

Suppose I have button inside a template

<template id="persons">
     <tr>
         <td></td>
         <td></td>
         <td><button type="button" id="delete" class="btn btn-danger">Delete</button></td>
     </tr>
</template>

Now im trying to add an event listener to the button by

this.oBtnDel = document.getElementById('delete');

this.oBtnDel.addEventListener("click", somefunc);

however im getting an error saying

Cannot read property 'addEventListener' of null

how can i fix this?

Nisarg
  • 13,121
  • 5
  • 31
  • 48
Beginner
  • 1,430
  • 1
  • 16
  • 32
  • This means that the button is not rendered yet. You can look into delegates instead' – Rajesh Aug 07 '19 at 05:15
  • Is the button element available in the `DOM` at the time of adding the listener? – Krishna Prashatt Aug 07 '19 at 05:15
  • Are you planning on adding that button to the DOM? You should try attaching the event handler after that. – Nisarg Aug 07 '19 at 05:16
  • Possible duplicate of [Why does jQuery or a DOM method such as getElementById not find the element?](https://stackoverflow.com/questions/14028959/why-does-jquery-or-a-dom-method-such-as-getelementbyid-not-find-the-element) – MofX Aug 07 '19 at 05:26

4 Answers4

3

Items in templates are not part of the regular DOM. They will not be there when you are binding the event listener. You will also have a problem with id="delete" if you have more than one as Ids must be unique.

What you need to do is use event delegation, and I will use a data attribute to identify the button.

Template

<template id="persons">
     <tr>
         <td></td>
         <td></td>
         <td><button type="button" data-action="delete" data-objectid="id to delete" class="btn btn-danger">Delete</button></td>
     </tr>
</template>

Javascript

//Bind the event to the parent table say it has an id of parentTable
this.oTable= document.getElementById('parentTable');    
this.oTable.addEventListener("click", function(event){
   //check the delete button was clicked
   if(event.target.dataset.action === "delete")
   {
       //Logic for delete goes here
       var idToDelete = event.target.dataset.objectid;
       /*Rest of your logic*/
   }
});

NOTE the code above is untested. If it doesn't work, you should be able to fill in the gaps with the links provided.

Further reading on event delegation: https://davidwalsh.name/event-delegate

Jon P
  • 17,053
  • 7
  • 44
  • 64
  • sir can i ask this part ? if(event.target.dataset.delete == "delete") should this be change to if(event.target.dataset.action== "delete") ? – Beginner Aug 07 '19 at 05:39
  • Correct, well spotted! Must be time for my afternoon coffe. – Jon P Aug 07 '19 at 05:40
  • why im i getting null in the event.target.dataset.objectid i just append the attribute just like this oCRUD.oTd[5].setAttribute("data-objectid", element.id); on the getPerson() and suddenly im getting null – Beginner Aug 07 '19 at 05:56
  • Data attributes are a little different to regular attributes you'd be better off with `oCRUD.oTd[5].dataset.objectid = element.id;` – Jon P Aug 07 '19 at 06:11
  • still im getting undefined when i console.log(event.target.dataset) im just getting the DOMStringMap {action: "delete"}action: "delete"__proto__: DOMStringMap there is no value for the objectid – Beginner Aug 07 '19 at 06:14
  • but when i inspect element the data-objectid is already define? – Beginner Aug 07 '19 at 06:17
  • 1
    Ahh I missed something, you're applying the data attribute to the `td` not the button. To apply it to the button try `oCRUD.oTd[5].querySelector("[data-action=delete]").dataset = element.id` – Jon P Aug 07 '19 at 06:23
1

According to MDN,

The HTML Content Template (<template>) element is a mechanism for holding HTML that is not to be rendered immediately when a page is loaded but may be instantiated subsequently during runtime using JavaScript.

Think of a template as a content fragment that is being stored for subsequent use in the document. While the parser does process the contents of the <template> element while loading the page, it does so only to ensure that those contents are valid; the element's contents are not rendered, however.

The contents of <template> are not yet rendered when you are trying to attach an event handler to the button. Try attaching the event handler after including the template to an element.

See the snippet below:

var template = document.getElementById("persons");
document.body.appendChild(template.content);

this.oBtnDel = document.getElementById('delete');
this.oBtnDel.addEventListener("click", () => console.log("click"));
<template id="persons">
     <tr>
         <td></td>
         <td></td>
         <td><button type="button" id="delete" class="btn btn-danger">Delete</button></td>
     </tr>
</template>
Community
  • 1
  • 1
Nisarg
  • 13,121
  • 5
  • 31
  • 48
  • sir can you look at my whole code https://stackoverflow.com/questions/57386589/refresh-table-after-a-successful-axios-post-request?noredirect=1#comment101256726_57386589 – Beginner Aug 07 '19 at 05:27
-1

Try like this.

 <script> 
        document.getElementById("delete").addEventListener("click", function(){ 
        // Write your function here
    }); 
        </script> 
Raahul
  • 379
  • 1
  • 2
  • 8
-1

This is return "null" error because tag is not define in HTML i convert to or any other tag ... it's solved.

<form id="persons">
    <tr>
        <td></td>
        <td></td>
        <td><button type="button" id="delete" class="btn btn-danger">Delete</button></td>
    </tr>
</form>

<script>
    function somefunc() {
        alert("hello world ...");
    }
    var oBtnDel = document.getElementById('delete');
   oBtnDel? oBtnDel.addEventListener("click", somefunc) : alert("false");
</script>
milad
  • 3
  • 4