I’m developing application using backbone.js & jquery. I have following code in model:
runReport: function() {
this.set({generatingReport: true});
//long computation...
this.set({generatingReport: false});
}
and following code in corresponding view (in initialize function):
...
var that = this;
...
this.model.bind("change:generatingReport", function() {
if(that.model.get("generatingReport") === true) {
$("#report").empty().append("<h1>Generating report...</h1>").show(0);
console.log("begin");
} else if(that.model.get("generatingReport") === false) {
$("#report").empty().append("<h1>Report generated</h1>").show(0);
console.log("end");
}
});
and here is code in view that run the action:
...
events {
"click #btn-run": "runReport"
}
...
runReport: function() {
this.model.runReport();
}
My problem is that that the “Generatin report…” message is not shown at all (log messages are printed). When the report is generated “Report generated” appears.
If I do following (see added alert in IF branch):
this.model.bind("change:generatingReport", function() {
if(that.model.get("generatingReport") === true) {
$("#report").empty().append("<h1>Generating report...</h1>").show(0);
console.log("begin");
alert("stop!");
} else if(that.model.get("generatingReport") === false) {
$("#report").empty().append("<h1>Report generated</h1>").show(0);
console.log("end");
}
});
then “Generating report…” is shown. In the “long computation…” part there is no hide jquery call that could possibly hide the message.
Any idea what is happening here?
I think what’s probably happening here is that the browser never has a chance to update the UI. Your long computation is all happening in the event handler for a click event. The browser probably (I say “probably” a lot here because I’m not really an expert in browser threading models!) dispatches the click event to your Javascript code, and then waits for your event handler to finish before updating/redrawing the UI. In this case, you’re not yielding control (finishing) until the long process is over, so the UI only redraws itself once at the end. The DOM’s #report node is changing internally in response to your code, but it doesn’t have a chance to redraw itself on screen until after your process finishes. I don’t know if this is optimal, but something like this might help:
I’m just using underscore’s delay() function there to postpone the long processing for 50 milliseconds. By doing so, the runReport() function can immediately exit, the click event handler that started the whole chain of events can finish executing, and the UI can redraw itself to show the “Generating report…” message. After a very short (50 milliseconds) delay, the long computation will begin, and when it’s done, generatingReport will set to false and the UI will update again.