KnockoutJS:可编辑网格的工作示例

时间:2015-04-29 13:04:41

标签: knockout.js datagrid

我需要一个允许在编辑和查看之间切换的网格。编辑完成后,用户可以选择是否要应用或取消对已编辑行进行的更改。这是一个例子,它完全符合我的需要:http://jsfiddle.net/peterf/8FMPc/light/

但不幸的是,这个JSFiddle不适用于KnockoutJS v.3.2.0: http://jsfiddle.net/8FMPc/315/ 当我单击“编辑”按钮时,输入没有值(水果名称)。 这似乎是数据绑定的一个问题:

<input type="text" class="edit" data-bind="value: name.editValue, visible: $root.isItemEditing($data)"  />

有谁知道,如何解决这个问题?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

我会使用ko.extenders分割您正在添加的状态...问题是editvalue observable在您单击编辑按钮之前不会初始化,因此在您第一次单击它时它不起作用,但在那之后确实有效。

理论上,你要做的一切都应该完全用扩展器来完成,而不是像这样添加功能。如果你只是想通过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 );   

});

答案 1 :(得分:0)

我知道它已经回答了,但是这个水果的例子也是我的痛苦。我出来了:

 <!-- ko if: $root.isItemEditing($data) -->
            <input type="text" class="edit" data-bind="value: name.editValue, visible: $root.isItemEditing($data)"/>
 <!-- /ko -->

在较旧版本的淘汰模型中,更频繁地重新定位,这就是它之前的工作原因。在较新的版本中:

  

首次评估绑定时editValue   孩子可观察到每个水果的可观察物(data-bind =“value:   name.editValue“)不存在。当你点击”编辑“链接时   editValue observable已创建,但是淘汰赛并不知道它有   重新绑定。

suggested answere

这也适用于小于3.0的版本