I have a viewModel with an observableArray of objects with observable variables.
My template shows the data with an edit button that hides the display elements and s
I needed something similar, and I couldn't use the protected observables, as I needed the computed to update on the temporary values. So I wrote this knockout extension:
This extension creates an underscore version of each observable ie self.Comments() -> self._Comments()
ko.Underscore = function (data) {
var obj = data;
var result = {};
// Underscore Property Check
var _isOwnProperty = function (isUnderscore, prop) {
return (isUnderscore == null || prop.startsWith('_') == isUnderscore) && typeof obj[prop] == 'function' && obj.hasOwnProperty(prop) && ko.isObservable(obj[prop]) && !ko.isComputed(obj[prop])
}
// Creation of Underscore Properties
result.init = function () {
for (var prop in obj) {
if (_isOwnProperty(null, prop)) {
var val = obj[prop]();
var temp = '_' + prop;
if (obj[prop].isObservableArray)
obj[temp] = ko.observableArray(val);
else
obj[temp] = ko.observable(val);
}
}
};
// Cancel
result.Cancel = function () {
for (var prop in obj) {
if (_isOwnProperty(false, prop)) {
var val = obj[prop]();
var p = '_' + prop;
obj[p](val);
}
}
}
// Confirm
result.Confirm = function () {
for (var prop in obj) {
if (_isOwnProperty(true, prop)) {
var val = obj[prop]();
var p = prop.replace('_', '');
obj[p](val);
}
}
}
// Observables
result.Properties = function () {
var obs = [];
for (var prop in obj) {
if (typeof obj[prop] == 'function' && obj.hasOwnProperty(prop) && ko.isObservable(obj[prop]) && !ko.isComputed(obj[prop])) {
var val = obj[prop]();
obs.push({ 'Name': prop, 'Value': val });
}
}
return obs;
}
if (obj != null)
result.init();
return result;
}
This extension will save you writing duplicates of each of your observables and ignores your computed. It works like this:
var BF_BCS = function (data) {
var self = this;
self.Score = ko.observable(null);
self.Comments = ko.observable('');
self.Underscore = ko.Underscore(self);
self.new = function () {
self._Score(null);
self._Comments('');
self.Confirm();
}
self.Cancel = function () {
self.Pause();
self.Underscore.Cancel();
self.Resume();
}
self.Confirm = function () {
self.Pause();
self.Underscore.Confirm();
self.Resume();
}
self.Pause = function () {
}
self.Resume = function () {
}
self.setData = function (data) {
self.Pause();
self._Score(data.Score);
self._Comments(data.Comments);
self.Confirm();
self.Resume();
}
if (data != null)
self.setData(data);
else
self.new();
};
So as you can see if you have buttons on html:
Cancel will undo and revert your observables back to what they were, as were save will update the real values with the temp values in one line