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); }); });
3 Réponses :
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);
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);
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); }); });
Est-ce que cela répond à votre question? Comment attendre qu'un élément existe?