Search code examples
javascriptmutation-observersmutation

Mutation observer - get all video tags of childs


I have a mutation observer (subtree: true). I shows all nodes added (I guess). When I monitor it with console.log(mutation.target.tagName) I see DIV and BODY and so on... HoweverI I need to add a listener now to all added tags (in fact one for onPlay and one for onPause)

Any idea how I can find (and react on) all added video tags in the childNodes added?

var target = document.body;
//then define a new observer
var bodyObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
    //How do i egt the video tags to add a listener?
    console.log("mutation detected: " + mutation.target.tagName);
    if (mutation.target.tagName == "VIDEO") {

        mutation.target.onclick =function () { console.log("The video has been clicked")}
    }
})
})
var bodyObserverConfig = { attributes: true, childList: true, subtree: true, 
characterData: true };
bodyObserver.observe(target, bodyObserverConfig);

Solution

  • The added nodes are listed in addedNodes property of a MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord) (mutation in your case). You have to iterate through this list and search for video nodes.
    Here is an example:

    If stackoverflow code snippet does not work - try codepen https://codepen.io/bsalex/pen/WMGvry .

    var target = document.body;
    //then define a new observer
    function addVideoHandler(node) {
      if (node.tagName == "VIDEO") {
        node.onclick = function() {
          alert("The video has been clicked");
        };
      }
    }
    var bodyObserver = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        //How do i egt the video tags to add a listener?
        console.log("mutation detected: " + mutation.target.tagName);
        mutation.addedNodes.forEach(addedNode => {
          addVideoHandler(addedNode);
          // it might be text node or comment node which don't have querySelectorAll
          addedNode.querySelectorAll && addedNode.querySelectorAll("video").forEach(addVideoHandler);
        });
      });
    });
    var bodyObserverConfig = {
      attributes: true,
      childList: true,
      subtree: true,
      characterData: true
    };
    bodyObserver.observe(target, bodyObserverConfig);
    
    // Example tools code below
    
    document
      .querySelector(".add-videos-here-action")
      .addEventListener("click", () => {
        const videoElement = document.createElement("video");
    
        document.querySelector(".add-videos-here").appendChild(videoElement);
      });
    
    document
      .querySelector(".add-nested-videos-here-action")
      .addEventListener("click", () => {
        const wrappingElement = document.createElement("div");
    
        wrappingElement.innerHTML =
          "<div><p><video /></p></div><div><video /></div>";
    
        document.querySelector(".add-videos-here").appendChild(wrappingElement);
      });
    
    document
      .querySelector(".add-not-videos-here-action")
      .addEventListener("click", () => {
        const notVideoElement = document.createElement("div");
        notVideoElement.textContent = "It is not a video";
    
        document.querySelector(".add-videos-here").appendChild(notVideoElement);
      });
    
    document
      .querySelector(".add-videos-here-too-action")
      .addEventListener("click", () => {
        const videoElement = document.createElement("video");
    
        document.querySelector(".add-videos-here-too").appendChild(videoElement);
      });
    video {
      min-width: 100px;
      min-height: 100px;
      border: 1px solid red;
    }
    <button class="add-videos-here-action">Add video</button>
    <button class="add-not-videos-here-action">Add NOT video</button>
    <button class="add-videos-here-too-action">Add another video</button>
    <div>
      <div class="add-videos-here">
        
      </div>
      
      <div class="add-videos-here-too">
        
      </div>
    </div>