使用 Knockout.js 更新 ejGrid 中的各个字段

Updating individual fields in an ejGrid with Knockout.js

Syncfusion Essential JS 库中的网格小部件 ('ejGrid') 支持 Knockout.js,但它似乎仅在数据源是普通对象的可观察数组时才起作用。如果数据源是一个可观察的视图模型数组,我该如何让它工作?例如:

var Order = function (data) {
    var self = this;
    self.OrderID = ko.observable(data.OrderID);
    self.CustomerID = ko.observable(data.CustomerID);
    self.ShipCity = ko.observable(data.ShipCity);
    self.Freight = ko.observable(data.Freight);
    self.EmployeeID = ko.observable(data.EmployeeID);
};

var rows =
    [ {
        OrderID: 10248,
        CustomerID: "VINET",
        ShipCity: "Reims",
        Freight: 11.61,
        EmployeeID: 4
    }, {
        OrderID: 10250,
        CustomerID: "HANAR",
        ShipCity: "Charleroi",
        Freight: 65.83,
        EmployeeID: 2
    }, {
        OrderID: 10251,
        CustomerID: "VICTE",
        ShipCity: "Reims",
        Freight: 41.34,
        EmployeeID: 1
    }, {
        OrderID: 10252,
        CustomerID: "SUPRD",
        ShipCity: "Madrid",
        Freight: 51.3,
        EmployeeID: 3
    }, {
        OrderID: 10253,
        CustomerID: "HANAR",
        ShipCity: "Rio de Janeiro",
        Freight: 58.17,
        EmployeeID: 3
    } ];

var rows2 = $.map(rows, function (data) { return new Order(data); });

var gridData = {
    dataSource: ko.observableArray(rows),    
    dataSource2: ko.observableArray(rows2)
};

ko.applyBindings(gridData);

$('#remove').click(function () {
    // both these work fine, since the array is observable
    gridData.dataSource.pop();
    gridData.dataSource2.pop();
});

$('#mutate').click(function () {
    // mutating the field does nothing (since it's not observable)
    (gridData.dataSource())[0].OrderID = 999999; 
    // this should work, however the table is full of gibberish
    (gridData.dataSource2)()[0].OrderID(999999);
});

JSFiddle:http://jsfiddle.net/hrapq7m2/

在上面的 fiddle 中,第一个网格使用普通对象的可观察数组,它显示正常,我们可以使用 'Remove Row' 按钮通过敲除删除行,但是,改变一个字段通过 'Mutate Row' 按钮的一行不起作用(所以它不应该)。第二个网格使用可观察的视图模型数组,因此 'Mutate Row' 按钮的实现应该有效,但是网格似乎试图显示可观察的对象而不是它们的当前值。

1: "The second grid uses an observable array of view models, and so the implementation of the 'Mutate Row' button should work, however the grid appears to be attempting to display the observable objects instead of their current values."

基本 JavaScript 网格不支持在网格单元格中呈现 KO 可观察字段。但我们可以通过以下解决方法实现您的要求。

//Workaround to show observable values in grid.
  var oldToString = Function.prototype.toString;

  Function.prototype.toString = function() {
    if(ko.isObservable(this))
       return this();
    return oldToString.call(this);
  }

使用上述解决方法将使可观察值显示在网格单元格中。

2: "The first grid uses an observable array of plain objects, which displays ok and we can remove rows via knockout using the 'Remove Row' button, however, mutating a field of a row via the 'Mutate Row' button doesn't work (and so it shouldn't)"

这是因为 ejGrid 将保持数组的长度而不是数组值的状态,因此更改网格外的字段值不会更新 UI.如果您希望更新后的值显示在网格中,您必须按如下方式刷新网格。

$('#mutate').click(function () {
// mutating the field does nothing (since it's not observable)
(gridData.dataSource())[0].OrderID = 999999; 
// this should work, however the table is full of gibberish
(gridData.dataSource2)()[0].OrderID(999999);

//Need to refresh grid to show updated value.
$("#Grid2").ejGrid("refreshContent");
});

已更新 Fiddle:http://jsfiddle.net/hrapq7m2/3/

如果您在数据源上调用 valueHasMutated,将重新检查 observableArray 并更新网格。

$('#mutate').click(function () {
    // mutating the field does nothing (since it's not observable)
    (gridData.dataSource())[0].OrderID = 999999;
    gridData.dataSource.valueHasMutated();
});

因此,您不需要让单个数据项成为可观察对象,但我想出了一种有趣的方法来使 ejGrid 处理可观察对象。如果您使用 Object.defineProperty 为属性定义 getter 和 setter,赋值语法与普通变量相同,但它是使用 observable 实现的。

function observableToProperty(obj, data, propertyName) {
    var observable = ko.observable(data[propertyName]);
    Object.defineProperty(obj, propertyName, {
        get: observable,
        set: observable
    });
}
var Order = function (data) {
    var self = this;
    observableToProperty(self, data, 'OrderID');
    observableToProperty(self, data, 'CustomerID');
    observableToProperty(self, data, 'ShipCity');
    observableToProperty(self, data, 'Freight');
    observableToProperty(self, data, 'EmployeeID');
};

现在两个数据源的更新语法相同。

$('#mutate').click(function () {
    // mutating the field does nothing (since it's not observable)
    (gridData.dataSource())[0].OrderID = 999999;
    gridData.dataSource.valueHasMutated();
    // this should work, however the table is full of gibberish
    (gridData.dataSource2)()[0].OrderID = 999999;
    gridData.dataSource2.valueHasMutated();
});

在这种情况下,使用 observable 没有任何优势,并且 observable 是完全私有的,因此您甚至无法订阅它们。但是您可以让它们易于访问,并根据需要对它们做一些有用的事情。您可以像使用底层可观察对象一样使用绑定中的属性。

如果不重写 ejGrid bindingHandler,则无法使网格单元单独响应其内容的更新。即使包装它也无济于事,因为您无权访问它在单元级别执行的操作(如果有的话)。因此,通知 observableArray 某些内容发生了变化是您可以合理地做的最好的事情。

http://jsfiddle.net/hrapq7m2/4/