0

Based on this question, I wrote the following code:

$(function() {
    $( document ).on('DOMNodeInserted',"span:contains('Suggested Post')", function() {
        console.log("New Suggested Post found");
    })
})

As I scroll down the page and these elements are created, I do not see the console message I expect to see. However, if I manually input $("span:contains('Suggested Post')").length in the console, the output continues to increase.

Ideas?

Snippet requested by @Barmar. It doesn't behave exactly like my real-world scenario, but it's still not right...

$(document).on('DOMNodeInserted', "div:contains('Banana')", function() {
  console.log("new banana detected!");
});

$('#btn').on('click', function() {
  var fruit = '';
  switch (Math.floor((Math.random() * 3) + 1)) {
    case 1:
      fruit = 'Apple'
      break;
    case 2:
      fruit = 'Orange'
      break;
    case 3:
      fruit = 'Banana'
      break;
    default:
      fruit = "WTF"
  }
  $('#fakeDocument').append('<div>' + fruit + '</div>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fakeDocument">
  <strong>Banana Detector</strong>
  <button id="btn" type="button">Add Banana!</button>
</div>
Community
  • 1
  • 1
JOATMON
  • 15,576
  • 31
  • 99
  • 188
  • With your delegation, your handler is only triggered if the elements are created **inside** an element that matches the selector, not if the element that's created matches the selector. – Barmar Nov 15 '16 at 19:35
  • ahhhhh, I see. Any suggestions for modification? – JOATMON Nov 15 '16 at 19:37
  • Hmm, I could be wrong about that. https://www.w3.org/TR/DOM-Level-3-Events/#event-type-DOMNodeInserted says that `event.target` is the node being inserted, not the container. And jQuery matches the selector against the target. – Barmar Nov 15 '16 at 19:42
  • Can you create a Stack Snippet that demonstrates the problem? – Barmar Nov 15 '16 at 19:46
  • Ummm, I kind of did. I'll work on it some more. – JOATMON Nov 15 '16 at 20:13
  • For some reason it fires every time but it fires twice when there is an actual match. Not sure why. – JOATMON Nov 15 '16 at 20:21

1 Answers1

2

You need to bind the delegation to the immediate parent of the elements that are being inserted.

The reason for this is that the DOMNodeInserted event bubbles up. If you bind it to an outer container, it will bubble up to a containing DIV, and that DIV will match :contains(Banana) because of the Banana Detector heading. And even if you move that out of the container, it will match because of previously added nodes that contain Banana.

This is why you got two firings when there was an actual match: it would fire once for the new element that matches, and again for the container that always matches.

I initially thought that event.StopPropagation() would solve the problem, but it doesn't. It will prevent double firings when there's an actual match. But it will still fire when there's no match -- the event doesn't fire on the new element (because it doesn't match), so event.stopPropagation() doesn't run, so it bubbles out to the container that matches.

$("#fakeDocument").on('DOMNodeInserted', "div:contains('Banana')", function() {
  console.log("new banana detected!");
});

$('#btn').on('click', function() {
  var fruit = '';
  switch (Math.floor((Math.random() * 3) + 1)) {
    case 1:
      fruit = 'Apple'
      break;
    case 2:
      fruit = 'Orange'
      break;
    case 3:
      fruit = 'Banana'
      break;
    default:
      fruit = "WTF"
  }
  $('#fakeDocument').append('<div>' + fruit + '</div>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fakeDocument">
  <strong>Banana Detector</strong>
  <button id="btn" type="button">Add Banana!</button>
</div>
Barmar
  • 596,455
  • 48
  • 393
  • 495