Search code examples
javascriptjqueryecmascript-6promisees6-promise

How to wait until an element exists with JavaScript?


I'm working with a proxy object where I detect a object value change and then load new content via AJAX, I use a setInterval function to wait until a the element that comes in the AJAX request exist and then execute a piece of code. I'm doing in this way because my case requires it. I made a short snippet example:

var handler = {
    makeThings: 0,
    otherStuff: 0
};
var globalHandler = new Proxy(handler, {
    set: function(obj, prop, value) {
        obj[prop] = value
        if (prop == "makeThings") {
            var clearTimeSearchProxy = setInterval(function() {
                if ($("p").length) {
                    console.log("The element finally exist and we execute code");
                    clearTimeout(clearTimeSearchProxy);
                }
            }, 100);
        }
        return true;
    }
});

$(document).ready(function() {
    $("button").on("click", function() {
        globalHandler.makeThings = 1;
        //This element comes with ajax but I use a setTimeout for this example
        setTimeout(function() {
            $("#newContent").append("<p>Ajax element</p>");
        }, 2000);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <button>New content</button>
  <div id="newContent"></div>
</body>

Now I'm wondering about how to improve the code in a cleaner, efficient and elegant way. I was thinking of using promises instead of setInterval to execute a code when the element that comes via AJAX exists in the DOM.

How can I make it work? Should I use other JavaScript functionality for this case instead of promises? I'm stuck with the promise to achieve what I need, this what I have tried so far.

var handler = {
    makeThings: 0,
    otherStuff: 0
};
var globalHandler = new Proxy(handler, {
    set: function(obj, prop, value) {
        obj[prop] = value
        if (prop == "makeThings") {
            var myFirstPromise = new Promise((resolve, reject) => {
                if ($("p").length) {
                    resolve("Exist");
                } else {
                    reject("It doesnt exist.");
                }
            });

            myFirstPromise.then((data) => {
                console.log("Done " + data);
            }).catch((reason) => {
                console.log("Handle rejected promise: " + reason);
            });
        }
        return true;
    }
});

$(document).ready(function() {
    $("button").on("click", function() {
        globalHandler.makeThings = 1;
        //This element comes with ajax but I use a setTimeout for this example
        setTimeout(function() {
            $("#newContent").append("<p>Ajax element</p>");
        }, 2000);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <button>New content</button>
  <div id="newContent"></div>
</body>


Solution

  • I finally made it with MutationObserverinterface in an easy way instead of with promises.

    var handler = {
        makeThings: 0,
        otherStuff: 0
    };
    var globalHandler = new Proxy(handler, {
        set: function(obj, prop, value) {
            obj[prop] = value
            if (prop == "makeThings") {
                var observer = new MutationObserver(function(mutations) {
                    if ($("p").length) {
                        console.log("Exist, lets do something");
                        observer.disconnect();
                    }
                });
                // start observing
                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            }
            return true;
        }
    });
    
    $(document).ready(function() {
        $("button").on("click", function() {
            $("p").remove();
            globalHandler.makeThings = 1;
            //This element comes with ajax but I use a setTimeout for this example
            setTimeout(function() {
                $("#newContent").append("<p>Ajax element</p>");
            }, 2000);
        });
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <body>
      <button>New content</button>
      <div id="newContent"></div>
    </body>