I sped up my server response times and suddenly had a strange issue: I ran into a problem where code was being executed before the browser could draw certain elements that need to be on screen first. Instead of the problem being that the code needed to be in $.ajax().done(), I need essentially a done
for the insertion of elements into the DOM.
The best option I've found so far is this answer to a similar question last year that uses async/await:
const checkElement = async selector => {
while ( document.querySelector(selector) === null) {
await new Promise( resolve => requestAnimationFrame(resolve) )
}
return document.querySelector(selector);
};
Which I can invoke in my own code then like this:
checkElement('#showFileBrowserContent').then( function (selector) {
loadDirectory (path, "", nextMode, articleId, siteId, currentSetting, fileBrowserPanel, callback, mode);
});
This seems to work just fine, but I was wondering if there's a way to make it work within a jQuery function just for neatness's sake, e.g.:
$('#showFileBrowserContent').checkElement().done( function () { loadDirectory (path, "", nextMode, articleId, siteId, currentSetting, fileBrowserPanel, callback, mode); });
I've never tried extending jQuery before, so I probably did this entirely incorrectly, but here is what I tried to make that happen:
jQuery.fn.checkElement = async function () {
var o = $(this[0]) // This is the element
// Also tried o === null without the $().
while ( $( o ) === null) {
await new Promise( resolve => requestAnimationFrame(resolve) )
}
return this;
};
This did not work. Is it a problem with using async/await within a jQuery function? Or is it a problem with my code?
Update: Here's the code in question that I'm trying to make sure is finished inserting into the DOM before I move on. It uses BootstrapDialog:
fileBrowserPanel = new BootstrapDialog({
title: title,
buttons: buttons,
cssClass: 'fileBrowser',
onhide: function(mode){
if (editorPanel !== null) {
editorPanel.open(); editorPanel.setAutodestroy(true);
}
}
});
var editorContents = '<div class="row"><div id="fileBrowserCurrentLocation" class="col-xs-8"></div><div id="fileBrowserToolbar" class="col-xs-4"><p><button type="button" class="btn btn-default" aria-label="Upload a File" id="launchFileUpload"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload a File</button></p></div></div>';
editorContents += '<div class="row"><div id="showFileBrowserContent" class="col-xs-12"><table id="loaderTable">' + loaderGraphic + '</table></div></div>';
fileBrowserPanel.setMessage(editorContents);
fileBrowserPanel.setType(BootstrapDialog.TYPE_INFO);
var response = fileBrowserPanel.open();
That code has a spinner graphic inserted where the actual document data should go in #showFileBrowserContent
. It then calls loadDirectory()
, which has the AJAX call to get the actual content and replaces #showFileBrowserContent
's contents with what is returned. However, without either a timer or the await
function, it appears the AJAX call completes and #showFileBrowserContent
doesn't yet exist. This wasn't a problem when my server response time was closer to 600ms, but when I knocked it down to closer to 200-300ms, the spinner would never go away and I noticed it appeared that was because the AJAX call completed before #showFileBrowserContent
existed.