I would actually recommend you update the viewmodel immediately and undo that change if the ajax call fails. It will make your app seem faster - since 90+% of your ajax calls will hopefully succeed, it makes no sense coding for the benefit of 10% of cases.
EDIT: I highly recommend this video. It supports this point brilliantly.
But this is how to do it:
The essence of it all is a intercepting computed
for your originalObservable
:
ko.computed({
read: function() {
return originalObservable();
},
write: function( newVal ) {
// perform ajax call
$.post( '<url>' , { data: originalObservable() } , function() {
// in your success callback
// update your observable
originalObservable( newVal );
});
// note: we get to this point without updating the originalObservable
// because this is part of the synchronous code
// where as the ajax call will, of course, be asynchronous
}
});
You can use this is many different ways:
-1- On your viewmodel as a separate property and bind your edit html to this
function Viewmodel() {
this.original = ko.observable();
this.editable: ko.computed( /* as above */ );
}
-2- A slight variation of (1), but cleaner, is to put the computed on the observable as a property:
function Viewmodel() {
this.original = ko.observable();
this.original.editable: ko.computed( /* as above */ );
}
-3- Create a custom binding which creates this computed for you, leaving your viewmodel even cleaner:
ko.bindingHandlers.myAjaxSave = {
init: function( element, valueAccessor ) {
var originalObservable = valueAccessor();
var editable = ko.computed({
read: function() {
return originalObservable();
},
write: function( newVal ) {
// perform ajax call
$.post( '<url>' , { data: originalObservable() } , function() {
// in your success callback
// update your observable
originalObservable( newVal );
});
// note: we get to this point without updating the originalObservable
// because this is part of the synchronous code
// where as the ajax call will, of course, be asynchronous
}
});
// this applies the binding to the HTML element
ko.applyBindingToNode( element , {
value: editable
});
}
}
You can now use this in your input HTML element like:
<input data-bind="myAjaxSave: Person.Name" />