Given the following snippet of code
var empowerInstance = null;
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);
}
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
window.addEventListener("DOMContentLoaded", function (event) {
console.log("DOM fully loaded and parsed");
if (typeof location.origin === "undefined")
window.location.origin = window.location.protocol + "//" + window.location.host;
document.getElementById("btnSendMessage").addEventListener("click", onClick_btnSendMessage);
});
Instead of wiring the button up , I'd like to fire the code from the activation of a Bootstrap tab event.
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
onClick_btnSendMessage(); // Naive way, as this does not wait
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
});
So my question is "How do I wait on this function to complete before changing the source of childIFrame?".
empowerInstance.document.hasChanged(hasChangedCallback);
I conceptually understand the use of Promises and Callbacks, but writing one that functions correctly is a different story.
UPDATED
This version is refactored to eliminate the button handler, thus improving readability.
The usage is also important. When the page loads for the first time it is positioned on a tab. This tab is associated to a document that is hosted in an iFrame. If the user edits this document then tries to change tabs, I'd like to invoke the check for being dirty/save, then once saved, move to the next tab/document. There is also the case that switching between tabs/documents won't cause a save because the document is not dirty.
var empowerInstance = null;
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
$(function () {
if (typeof location.origin === "undefined") {
window.location.origin = window.location.protocol + "//" + window.location.host;
}
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
var childIFrame = $("#editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame[0].contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);// Need to wait for completion
var target = $(e.target).attr("data-EditorUrl"); // activated tab
childIFrame.attr("src", target);
});
});
Thank you, Stephen
I've refactored your code to show how this can be done using promises.
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
var doc = empowerInstance.document;
return hasChanged(doc).then(function() { return save(doc) })
}
function hasChanged(doc) {
return new Promise(function(resolve, reject) {
doc.hasChanged(function(returnValue) {
if (returnValue.success === true && returnValue.isDirty === true) {
resolve(returnValue)
} else {
reject(returnValue)
}
})
})
}
function save(doc) {
return new Promise(function(resolve, reject) {
doc.save(function(returnValue) {
if (returnValue.success === false) {
console.log(returnValue.message);
reject(returnValue)
} else {
resolve(returnValue)
}
})
})
}
// ------
$('a[data-toggle="tab"]').on("shown.bs.tab", function(e) {
onClick_btnSendMessage().then(function() {
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
}).catch(function(error) {
// handle the error
console.error('Error!', error)
})
});