-1

I am using jquery and I want to execute a function after counting the number of children of an element. My element has a child and I want to execute a function after it became 2 or more. This child appending is handled by some other JavaScript file and I just want to listen for adding a child in that element. That append child happens after an async operation so it may not be executed at the time of checking children count. Here is what I tried:

let i = 0;
const interVal = setInterval(() => {
    const parent = $(".parent");

    if (parent && parent.length > 1) {
        console.log("Child has been appended.");
    } else {
        console.log("Child has not been appended!");

        if (i >= 50000) {
            console.error("A lot of conditions executed and cannot bother browser anymore.");

            clearInterval(interVal);
        }
    }

    i++;
}, 1);

This code has a problem. It is checking after a period of time. What can I replace with it?

m sh
  • 41
  • 6

2 Answers2

2

MutationObserver is what you need.

Here is the MDN example very slightly modified.

// simulating some content appended in a later time (async)
setTimeout(function () {
  $(".parent").append("<div>I am a div appended after page load!</div>");
}, 5000);

// Mutation observer
var targetNode = $(".parent")[0];

// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
const callback = function (mutationsList, observer) {
  // Use traditional 'for loops' for IE 11
  for (const mutation of mutationsList) {
    if (mutation.type === "childList") {
      console.log("A child node has been added or removed.");

      // How many children now?
      console.log(`There is ${$(".parent").children().length} child elements`);
      
      // List them
      $(".parent").children().each(function(index){
        console.log(`#${index+1}- ${$(this)[0].tagName} - ${$(this)[0].innerText}`)
      })
      
    } else if (mutation.type === "attributes") {
      console.log("The " + mutation.attributeName + " attribute was modified.");
    }
  }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
  <h1>Hello! Another child will be appended...</h1>
</div>

To put an end to the observer... Like if a condition is reached at some point... Use:

observer.disconnect();
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
  • If you want to just listen to direct child changes, don't include subtree option to the config – Emre Oct 12 '22 at 15:36
1

Actually, it's all about if-else.

Let me explain it to you.

<div id="parent">
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
  </ul>
</div>

to reach the count of children, you should use .length like this;

var count = $("#parent li").length;

or this way

var count = $("#parent ul").children().length;

Now let's say you want to execute if the count of children is bigger than 2 or whatever you want;

if(count>2){
    alert("I am bigger than 2, mate");
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
Erencan
  • 185
  • 6
  • That child appending happens after an async operation. So maybe it is not appended in that time. – m sh Jan 28 '21 at 13:10