I\'m using Mithril JS in a project and I\'m having trouble understanding exactly how to go about hooking into the Ajax lifecycle. Like if I have an Ajax request takes awhile, I
One way is to wrap m.request
in another function that returns both the completion state (based on a flag that you set via the m.request promise chain), and the data, and then use the background: true
option to prevent the deferral of the redraw, and also bind m.redraw
to the promise chain in order to have redrawing happen after the request.
This was originally described here: https://github.com/lhorie/mithril.js/issues/192
var requestWithFeedback = function(args) {
var completed = m.prop(false)
var complete = function(value) {
completed(true)
return value
}
args.background = true
return {
data: m.request(args).then(complete, complete).then(function(value) {
m.redraw()
return value
}),
ready: completed
}
}
var MyController = function() {
this.things = requestWithFeedback({method: "GET", url: "/things"})
}
var myView = function(ctrl) {
return !ctrl.things.ready() ? m("img[src=loading.gif]") : m("ul", [
ctrl.things.data().map(function(thing) {
return m("li", thing.name)
})
])
}
m.module(document.body, {controller: MyController, view: myView})
I found what I think is an elegant way to do this, based on the principle that Mithril re-renders the entire UI (with differencing) on model update. The following example is for saving an inline update.
When I have some part of the model which is changing via AJAX, I set a temporary flag in the model (you can as easily do it in the view-state model if you want to keep it separate), and on completion, I just delete the flag and invoke m.redraw():
function updateRecord(ctl,evt,row,idx,rcd) {
rcd._action="save";
apiSender({ method: "PATCH", url: apiUrl, data: dropFlags(rcd) }).then(done,fail).then(null,logObject);
function done(rspdta) {
delete rcd._action;
m.redraw();
};
function fail(rspdta) {
ajaxError(ctl,rspdta,"Update customer "+rcd.CustomerId+" ("+rcd.ContactName+")");
rcd._action="edit";
m.redraw();
};
}
In the view, which is rebuilt from the model data, I condition on the flag:
if (rcd._action=="edit" ) { con=crtListRecordView_Edit (rcd,idx ); }
else if(rcd._action=="save" ) { con=crtListRecordView_Waiting(rcd,idx,"Saving" ); }
else if(rcd._action=="delete" ) { con=crtListRecordView_Waiting(rcd,idx,"Deleting" ); }
else if(rcd._action=="merge" ) { con=crtListRecordView_Waiting(rcd,idx,"Merging" ); }
else if(rcd._action=="refresh") { con=crtListRecordView_Waiting(rcd,idx,"Refreshing"); }
else { con=crtListRecordView_Normal (rcd,idx ); }
return m("tr", con);
This allows multiple concurrent actions on different records, and a polished, clear and unobtrusive feedback to the user.
Here's what it looks like:
Normal:
Editing:
Saving: