Home > other >  How to keep track of dynamically added nodes using MutationObserver?
How to keep track of dynamically added nodes using MutationObserver?

Time:11-22

Context: The code is from the "content-script" of a chrome extension.

Given a target node, i would like to get every childNode(a div) and add a button on it.

I tried the simplest solution:

const target = document.querySelector(targetSelector);
const childNodes = target.childNodes;
childNodes.forEach(node => { //some function that add a button on this node});

Obviously, it works untill i scroll down the page, when new nodes are added on the DOM, and I can't keep track of them anymore.

Thus i decided to try with MutationObserver:

const target = document.querySelector(targetSelector);
const config = { childList: true, subtree: true };

const callback = (mutationList, observer) => {
  for (const mutation of mutationList) {
      console.log(mutation); //it doesn't return the node, but some kind of mutation object, so i can't get the refernce and work whit it.    
  } 
};

const observer = new MutationObserver(callback);

observer.observe(target,config);

There's a solution? Can i finally keep track of new added nodes and work with them?

EDIT: As @Jridyard suggested, i tried both "target" property and "mutation.addedNodes" property. This partially fixed the problem, in the sense that I finally got the references to the nodes initially, but not the dynamically loaded ones in the DOM, getting this error when I try to access the innerText property.

index2.js:52 Uncaught TypeError: Cannot read properties of undefined (reading 'innerText')
    at MutationObserver.callback 

Example:

const callback = (mutationList, observer) => {
        for(const mutation of mutationList) {
            //works with the initially loaded nodes,not tracking the others dinamically loaded after page scroll.
            /*if(mutation.target.classList[0] === "Comment") {
                console.log(mutation.target.innerText);
            } */ 
  
            //works with the initially loaded nodes, the gives me the above error with the others nodes dinamically loaded after page scroll.
            if(mutation.addedNodes[0] !== null) {
                console.log(mutation.addedNodes[0].innerText);
            }     
        }
    };

CodePudding user response:

I finally found a solution (not written by me, courtesy of a reddit user) and figured out that the initial problem stemmed from Reddit. Because I tried to do the same on youtube and it worked fine. In practice Reddit updates parts of a comment at different times, so simply monitoring the added nodes(as I did above) was not enough, but the comments had to be parsed after each mutation in the DOM. Probably computationally very inefficient, but currently working.

The code below shows the solution tailored for reddit:

function processComment(comment)
{
    const avatar_link = comment.querySelector("[data-testid=comment_author_icon]");
    const user_link = avatar_link?.getAttribute("href");
    const user_picture_link = avatar_link?.querySelector("img")?.getAttribute("src");
    
    const user_name = comment.querySelector("[data-testid=comment_author_link]")?.textContent;
    const body = comment.querySelector("[data-testid=comment]")?.textContent;
    
    return {
        user_link,
        user_picture_link,
        user_name,
        body,
        div: comment,
    };
    
}
 
function getComments(parent)
{
    return [...(parent ?? document).querySelectorAll(".Comment")].map(processComment);
}
 
function observeComments(callback, parent)
{
    parent ??= document;
    
    const mo = new MutationObserver(() => getComments(parent).map(callback));
    
    mo.observe(parent, {attributes: true, childList: true, subtree: true});
    
    return mo;
}
 
observeComments((m)=>console.log(m.body));

  • Related