This question isn’t exactly typescript related but without the context it would be unclear why I would even require such behavior. Should be relatively straight forward to understand whether you know Typescript or not.
I have a dialog class implementation in Typescript that looks something like this (only showing relevant methods and fields):
class BaseDialog{
...
public dialogEl: JQuery;
public AjaxLoadContent(route: string) {
if (this.dialogEl !== undefined)
this.dialogEl.load(route);
return this;
}
public HtmlLoadContent(html: string) {
if (this.dialogEl !== undefined)
this.dialogEl.empty().html(html);
return this;
}
public Show() {
if (this.dialogEl !== undefined)
this.dialogEl.dialog("open");
}
...
}
I’m returning this from AjaxLoadContent() and HtmlLoadContent() so that I can chain a call to Show() as follows:
var dialog = new BaseDialog();
dialog.AjaxLoadContent("/Account/Login").Show(); //Ajax call
dialog.HtmlLoadContent(someHtml).Show(); //Load from variable, no ajax call
I find this chaining syntax very clean and logical so I want to stick with it, however, in the ajax scenario, Show() gets called before ajax load() completes so the dialog opens, then there is a delay before the content appears. I can’t provide a callback to load() since I’d like to explicitly chain Show() onto the call instead of calling it internally…therefore, I need some kind of synchronous mechanism.
I’m now looking into Frame.js to accomplish this “synchronous” style without hanging the browser with something like $.ajaxSetup({async: false;}). Here is the answer I was hoping would work: https://stackoverflow.com/a/10365952
However, the following code still has the delay:
public AjaxLoadContent(route: string) {
if (this.dialogEl !== undefined){
var that = this;
Frame(function (next) {
$.get(route, next);
});
Frame(function (next, response) {
that.dialogEl.html(response); //Breakpoint 1
});
Frame.init();
return this; //Breakpoint 2
}
}
However this doesn’t seem to work as Breakpoint 2 gets hit first despite the explicit control flow I’ve defined. The Show() call happens immediately after return this (therefore loading a blank dialog), then finally that.jQueryDialog.html(response) gets called from the second Frame, loading the content after the dialog has already been shown (therefore still a delay).
How can I accomplish this synchronous behavior?
This is exactly (IMO) what JQueryDeferred is for. You can use that for all this without needing to add another dependency on Frame.js. The easiest way to do this would be to return a JQueryPromise from each Async method, like so:
That’s not quite as clean an interface, but the alternative is to do some awfully clever coding whereby your class throws each Deferred into a FIFO queue, and each subsequent method waits on the previous Deferred in the queue before it starts executing. Certainly possible, and if you’re designing this API for significant external consumption, it might be worth doing. But if you’re just planning to use it for some internal project, it sounds like too much work and maintenance to me. (Just my opinion, of course :-).
(Other problems with your proposed interface: (1) it doesn’t have any way of handling errors, analagous to the
JQueryDeferred.fail()handler; and (2) it doesn’t have any way of doing any external processing in-between calls to your class. What if you wanted to do a transform on the content before you called theShow()method?)