1
votes

Comment attendre qu'un élément existe avec JavaScript?

Je travaille avec un objet proxy où je détecte un changement de valeur d'objet puis charge un nouveau contenu via AJAX, j'utilise une fonction setInterval pour attendre qu'un élément qui vient dans la requête AJAX existe, puis exécutez un morceau de code. Je fais de cette façon parce que mon cas l'exige. J'ai fait un court exemple d'extrait:

<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>
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);
    });
});

Maintenant, je me demande comment améliorer le code d'une manière plus propre, efficace et élégante. Je pensais utiliser des promesses au lieu de setInterval pour exécuter un code lorsque l'élément qui vient via AJAX existe dans le DOM .

Comment puis-je le faire fonctionner? Dois-je utiliser une autre fonctionnalité JavaScript pour ce cas au lieu de promesses ? Je suis coincé avec la promesse de réaliser ce dont j'ai besoin, c'est ce que j'ai essayé jusqu'à présent.

<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>
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);
    });
});


1 commentaires

Est-ce que cela répond à votre question? Comment attendre qu'un élément existe?


3 Réponses :


1
votes

rxjs peut grandement simplifier ce que vous essayez de faire. Une implémentation très basique, utilisant uniquement un sujet et un abonnement:

<script src="https://unpkg.com/rxjs@6.5.2/bundles/rxjs.umd.min.js"></script>
const {
  Subject
} = rxjs;

const sub = new Subject();

sub.subscribe(e => {
  console.log(`received data ${e}`);
  // do your thing
});

// simulate something async
setTimeout(() => {
  sub.next('foo');
}, 1000);


0 commentaires

2
votes

N'attendez pas . Abonnez-vous plutôt pour être notifié d'un changement dans l'élément cible.

L'API à utiliser pour écouter les changements dans l'arborescence DOM est le MutationObserver .

L'interface MutationObserver offre la possibilité de surveiller les modifications apportées à l'arborescence DOM. Il est conçu pour remplacer l'ancienne fonctionnalité Mutation Events qui faisait partie de la spécification DOM3 Events.

Utilisez-le pour observer le changement dans un élément comme suit:

// You selected `$("p")` in your snippet, suggesting you're watching for the inclusion of 'any' `p` element.
// Therefore we'll watch the `body` element in this example
const targetNode = document.body;

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

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    for(let mutation of mutationsList) {

        if ( mutation.type === "childList" ) {
            continue;
        }

        const addedNodes = Array.from( mutation.addedNodes) ;

        if ( addedNodes && addedNodes.some( node => node.nodeName === "P" ) ) {
            observer.disconnect();

            console.log("The element finally exist and we execute code");
        }
    }
};

// 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);


0 commentaires

4
votes

Je l'ai finalement fait avec MutationObserver interface de manière simple plutôt qu'avec promises.

<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>
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);
    });
});


0 commentaires