Knockout链式计算的observable在更新时抛出异常

时间:2014-01-31 02:48:44

标签: javascript knockout.js

我正在使用Knockout 3来构建呈现为表格的可编辑网格。网格由Row对象组成,每行一个。在一行内是一个单元格数组(每列一个),然后在每个单元格内部是一个或多个Slot对象。插槽在表格单元格中呈现为一个列表。

外部行定义了一个RowIndex observable,其中的Cells有一个计算的observable,它读取行的RowIndex,而Slots有一个计算的observable,它从Cell中读取RowIndex。

问题在于,当我在一行上设置一个新的RowIndex时,它会传播到Cell,但是当Cell包含Slots时,KO会抛出一个异常:“对象[object object]的未捕获的TypeError:属性'回调'是不是“在knockout-3.0.0.debug.js第1021行的功能”。从Chrome开发者工具中,我看到订阅的callback属性确实未定义。

如果Cell不包含任何插槽,则在Row上设置RowIndex会导致它传播到Cell而没有问题。

var Row = function(data) {
  var self = this;

  this.Cells = [];
  this.RowIndex = ko.observable(data.rowIndex);

  // omitted code...
}

var Cell = function(data, row) {
  var self = this;
  this.row = row;

  this.Enabled = ko.observable(true);

  // When row is disabled, disable the cell
  row.Enabled.subscribe(function (value) {
    if (value == false) {
      self.Enabled(false);
    }
  });

  // RowIndex comes from parent row
  this.RowIndex = ko.computed(function () {
    return self.row.RowIndex(); 
  }, this);
  // omitted code ...
}

var Slot = function(data, cell, enabled) {
  var self = this;
  this.cell = cell;

  // RowIndex is cells's RowIndex
  this.RowIndex = ko.computed(function() {
    return self.cell.RowIndex();
  }, this);

  // Any change marks slot as dirty
  self.Title.subscribe(this.updated);
  self.SeatCount.subscribe(this.updated);
  self.RowIndex.subscribe(this.updated);

  this.updated = function() {
    if (self.Action() == actions.None)
    {
      self.Action(actions.Update);
    }
  }

  // When cell is disabled, I feel disabled, too.
  cell.Enabled.subscribe(function(value) {
    if (value == false) {
        self.Enabled(false);
    }
  });

  // omitted code 
}

var ViewModel(colHeadings, rowHeadings, slots) {
  var self = this;

  // Code omitted to iterate the slots and build the rows
  // and cells

  // Invoked on a click to add a row at index
  this.addRow = function(index) {
    var row = new Row({ heading: "New Row", rowIndex: index });
    for (var ci=0; ci<this.columnCount; ci++) {
        var c = new Cell({ colIndex: ci }, row);
        row.Cells.push(c);
    }
    self.RowData.splice(index, 0, row);
    self.renumberRows();
  };

  // Invoked on a click to remove (disable) a row
  this.removeRow = function(row) {
    row.Enabled(false);
    self.renumberRows();
  };

  // Sequentially number the enabled rows
  this.renumberRows = function() {
    var index = 0;
    for (var ri=0; ri<self.RowData().length; ri++) {
      var row = self.RowData()[ri];
      if (row.Enabled()) {
        row.RowIndex(index);
        index++;
      }
    }
  };
}

当我在ViewModel上通过addRow插入新行时,会分配RowIndex,并将其传播到Cells。这太好了。但是新的Row的单元格还没有任何插槽,所以到目前为止没有错误。但是我必须重新编号行,以便RowIndex是顺序的。一旦我在一个Row上设置了RowIndex,并且Cell有一个Slot,我就会得到异常。 removeRow也是如此。

1 个答案:

答案 0 :(得分:3)

问题在于,您已在undefined的此部分代码中使用Slot回调创建了手动订阅:

// Any change marks slot as dirty
self.Title.subscribe(this.updated);
self.SeatCount.subscribe(this.updated);
self.RowIndex.subscribe(this.updated);

this.updated = function() {
  if (self.Action() == actions.None)
  {
    self.Action(actions.Update);
  }
}

正如您所看到的,您在分配之前使用的是this.updated。那么它就是undefined