我会使用 ko.extenders 拆分您添加的状态内容...问题是可观察的 editvalue 在您单击编辑按钮之前不会初始化,因此在您第一次单击它时它不起作用,但在那之后确实有效。
理论上,您尝试做的所有事情都应该完全使用扩展程序来完成,而不是像这样添加函数。如果你只是想通过 fn 能力添加功能,我认为它们应该是完全无状态的。
小提琴:
http://jsfiddle.net/brettwgreen/zfxmac7z/
JS:
/*----------------------------------------------------------------------*/
/* Observable Extention for Editing
/*----------------------------------------------------------------------*/
ko.extenders.editable = function(target, option) {
if (Array.isArray(target()))
target.editValue = ko.observableArray(target().slice());
else
target.editValue = ko.observable(target());
};
ko.observable.fn.beginEdit = function (transaction) {
var self = this;
var commitSubscription,
rollbackSubscription;
self.dispose = function () {
// kill this subscriptions
commitSubscription.dispose();
rollbackSubscription.dispose();
};
self.commit = function () {
// update the actual value with the edit value
self(self.editValue());
// dispose the subscriptions
self.dispose();
};
self.rollback = function () {
// rollback the edit value
self.editValue(self());
// dispose the subscriptions
self.dispose();
};
// subscribe to the transation commit and reject calls
commitSubscription = transaction.subscribe(self.commit,
self,
"commit");
rollbackSubscription = transaction.subscribe(self.rollback,
self,
"rollback");
return self;
}
/*----------------------------------------------------------------------*/
/* Item Model
/*----------------------------------------------------------------------*/
function Fruit( name, colour) {
var self = this;
// extend to add the editable capability
// this allows them to initialize right out of the gate
self.name = ko.observable(name).extend({ editable: true });
self.colour = ko.observable(colour).extend({ editable: true });
};
Fruit.prototype.beginEdit = function(transaction) {
this.name.beginEdit(transaction);
this.colour.beginEdit(transaction);
}
/*----------------------------------------------------------------------*/
/* View Model
/*----------------------------------------------------------------------*/
function FruitColourViewModel() {
var self = this;
// data
self.availableColours = [];
self.fruits = ko.observableArray([]);
self.editingItem = ko.observable();
// create the transaction for commit and reject
self.editTransaction = new ko.subscribable();
// helpers
self.isItemEditing = function(fruit) {
return fruit == self.editingItem();
};
// behaviour
self.addFruit = function () {
var fruit = new Fruit("New fruit", self.availableColours[0]);
self.fruits.push(fruit);
// begin editing the new item straight away
self.editFruit(fruit);
};
self.removeFruit = function (fruit) {
if (self.editingItem() == null) {
var answer = true; // confirm('Are you sure you want to delete this fruit? ' + fruit.name());
if (answer) {
self.fruits.remove(fruit)
}
}
};
self.editFruit = function (fruit) {
if (self.editingItem() == null) {
// start the transaction
fruit.beginEdit(self.editTransaction);
// shows the edit fields
self.editingItem(fruit);
}
};
self.applyFruit = function (fruit) {
// commit the edit transaction
self.editTransaction.notifySubscribers(null, "commit");
// hides the edit fields
self.editingItem(null);
};
self.cancelEdit = function (fruit) {
// reject the edit transaction
self.editTransaction.notifySubscribers(null, "rollback");
// hides the edit fields
self.editingItem(null);
};
}
/*----------------------------------------------------------------------*/
/* KO Page Binding */
/*----------------------------------------------------------------------*/
$(document).ready(function() {
// create the model
var model = new FruitColourViewModel();
model.availableColours = ["Blue", "Green", "Orange", "Red", "Yellow"];
var initData = [
new Fruit( "Apple", "Green"),
new Fruit( "Banana", "Yellow"),
new Fruit( "Orange", "Orange"),
new Fruit( "Strawberry", "Red")
];
model.fruits(initData);
// bind model to the html
ko.applyBindings( model );
});