0

In my code, I have a h1 container with h1 element inside like below :

<div id="container_h1"><h1 id="h1">Title H1</h1></div>

Then, I attach an event listener to h1 element in order to alert h1 text when the user clicks on h1 element :

var h1 = document.getElementById("h1");
h1.addEventListener(
                        "click", 

                        function()
                        {
                            alert(h1.innerHTML);
                        },

                        false                       
                    );

Then, I have 2 buttons for removing and inserting h1 element, like below :

<input type="button" value="remove H1" onclick="remove_h1();">
<input type="button" value="insert H1" onclick="insert_h1();">

//container_h1 element :
var container_h1 = document.getElementById("container_h1"); 

//Remove h1 :
function remove_h1()
{
    container_h1.innerHTML = "";    
}

//Re-appear h1 :
function insert_h1()
{
    container_h1.innerHTML = '<h1 id="h1">Title H1</h1>';   
}

The problem :

When I make disappear h1 element by clicking "remove H1" button then make reappear h1 element by clicking "insert H1" button, and then I click on h1 element, h1.addEventListerner in the code has no effect, no alert is triggered.

So how can I re-attach the same event listener to h1 element when this h1 element reappears ?

Thank you.

totoaussi
  • 712
  • 1
  • 11
  • 27
  • By this code container_h1.innerHTML = "" it not removing the h1 element but empty the inside html content. – Hanif Dec 25 '17 at 18:19
  • It's not the problem. The problem is when you make re-appear h1 element by clicking "insert H1" button and afterward you click the h1 element, no alert is triggered, the h1.addEventListener in the code has no effect. – totoaussi Dec 25 '17 at 18:22
  • 2
    You have to add the listener again the the new element. The old listener is gone since the old element is gone – charlietfl Dec 25 '17 at 18:26
  • @charlietfl yes it's what I want, but how can I do this ? – totoaussi Dec 25 '17 at 18:28
  • Exactly the same way you added it the first time – charlietfl Dec 25 '17 at 18:29
  • @totoaussi I know this is not your problem. I'm not provided any solution by my comment but trying to give you hints. – Hanif Dec 25 '17 at 18:29
  • @charlietfl I can't see how i can do that... – totoaussi Dec 25 '17 at 18:30
  • Maybe you would be better off setting display to none rather than deleting the element. – Mark Dec 25 '17 at 18:32
  • @Mark_M no I can't, because my code is just a simple example, in my real code, the element to remove is not a h1 element but a select element which options list changes by clicking an other select. – totoaussi Dec 25 '17 at 18:35

2 Answers2

5

Instead of h1.addEventListener(...) add

document.body.addEventListener('click', function(element) {
    if (element.target.nodeName == 'H1') {
        // your code
    }
})

So you bind event listener to body rather than h1. The thing is that your h1.addEventListener(...) is only applied on currently in DOM existing <h1> elements, but not on dynamically created ones.

http://www.theappguruz.com/blog/dynamic-event-binding-demo-jquery

In jQuery, how to attach events to dynamic html elements?

Jozef Cipa
  • 2,133
  • 3
  • 15
  • 29
  • Thank you very much. It's the solution. Yes, addEventListener is erased when the element attached is removed from DOM. – totoaussi Dec 25 '17 at 18:39
  • I'd just like to add, if possible, when doing event delegation like this it is best to attach the event handler at the lowest possible place in the DOM, rather than directly to the body. If all of the H1 elements have a common parent that isn't body, that would be the place to do it. That way, the click handler won't be firing every time ANYTHING on the page is clicked, only when things inside that common parent element are clicked. – Useless Code Dec 25 '17 at 22:55
  • @UselessCode of course, you're right :) It was just an example of how to do it. Also, on page should be only one `h1` element :) – Jozef Cipa Dec 25 '17 at 23:03
0

As Jozef Cipa's answer recommended, event delegation would probably be the best approach for doing what you are trying to accomplish. Without good reason to do something else, that is the way to go.

That said, it is also possible to detect elements being added/removed from the page using Mutation Observers and dynamically add event handlers.

var container_h1 = document.getElementById("container_h1"); 

function remove_h1(){
    container_h1.innerHTML = "";    
}

function insert_h1() {
    container_h1.innerHTML = '<h1 id="h1">Title H1</h1>';   
}


let h1ClickHandler = function(evt) {
    alert(evt.target.innerHTML);
  },
  addH1ClickHandler = function (nodes) {
    nodes.forEach(function (node) {
      node.addEventListener("click", h1ClickHandler, false);
    });
  },
  h1Added = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList' && mutation.addedNodes.length > 0) {
          addH1ClickHandler(mutation.addedNodes);
        }
    }
  };

// add click handlers to any existing h1 tags on load
addH1ClickHandler(container_h1.querySelectorAll('h1'));

// start observing for new h1 tags being added
var observer = new MutationObserver(h1Added);
observer.observe(container_h1, {
  childList: true
});
<input type="button" value="remove H1" onclick="remove_h1();">
<input type="button" value="insert H1" onclick="insert_h1();">

<div id="container_h1"><h1 id="h1">Title H1</h1></div>
Useless Code
  • 12,123
  • 5
  • 35
  • 40