1

这是JS代码:

function ProductViewModel() {
  // Init.
  var self = this;
  self.products = ko.observableArray();
  self.singleProduct = ko.observable();
  var mappedProducts;

  // Initialize table here.
  $.getJSON("/admin/test", function(allData) {
    mappedProducts = $.map(allData, function(item) { return new Product(item);});
    self.products(mappedProducts);

    self.oTable = $('#products-table').dataTable( {
      "aoColumns": [
        { "bSortable": false, "mDataProp": null, sDefaultContent: '' },
        {"mData": "name"}, 
        {"mData": "dealer"},
        {"mData": "cost"},
        {"mData": "price"}, 
        { "bSortable": false, sDefaultContent: '' }
      ],
    });
  });

  // Here i'm using the basic switch pattern, as from KO tutorials.
  // This is intended for showing a single product form.
  self.edit = function(product) {
    self.singleProduct(product);
  }

  // This is intended to hide form and show list back.
  self.list = function() {
    self.singleProduct(null);
  }

  // This is the form save handler, actually does nothing 
  // but switch the view back on list.
  self.doEdit = function(product) {
    self.list();
  } 
}



// My model.
function Product(item) {
  this.name = ko.observable(item.name);
  this.dealer = ko.observable(item.dealer);
  this.cost = ko.observable(item.cost);
  this.price = ko.observable(item.price);
  this.picture = ko.observable();
}

这是我的标记:

<table id="products-table" class="table table-striped table-bordered table-hover">
        <thead>
          <tr>
            <th>Pic</th>
            <th>Name</th>
            <th>Dealer</th>
            <th>Cost</th>
            <th>Price</th>
            <th>Actions</th>
          </tr>
        </thead>

        <tbody data-bind="foreach: $parent.products">
          <tr>
            <td><span data-bind='ifnot: picture'>-</span></td>
            <td><a data-bind="text: name"></a></td>
            <td><span data-bind='text: dealer'></span></td>
            <td><span data-bind='text: cost'></span></td>
            <td><span data-bind='text: price'></span></td>
            <td>
              <button data-bind='click: $root.edit'><i class='icon-pencil'></i>
              </button>
            </td>
          </tr>
        </tbody>
      </table>

当我点击编辑按钮,触发 $root.edit 处理程序时,会显示一个表单,因为

<div data-bind='with: singleProduct'>

我做了绑定。在这个绑定里面我有一个表格,有一个

<input data-bind="value: name" type="text" id="" placeholder="Name"
> class="col-xs-10 col-sm-5">

场地。

问题:当我编辑输入字段中的值时,数据表中的相关行没有更新。我尝试了一个没有数据表插件的基本表,它确实有效,这意味着如果我更改值,表中的行会正确更新。

这里有什么问题?

== 编辑 ==

我发现将绑定点移动到表 TD 解决了问题,但我仍然不知道为什么。

          <tr>
            <td data-bind="text: name"></td>
            <!-- More columns... -->
          </tr>

上面的代码现在可以正常工作了。为什么 ?

== 编辑2 ==

现在我解决了第一个问题,第二个问题来了。我像这样实现了我的“保存新”方法

self.doAdd = function(product) {
    $.ajax("/product/", {
      data: ko.toJSON({ product: product }),
      type: "post", contentType: "application/json",
      success: function(result) { alert('ehh'); }
    }).then(function(){
      self.products.push(product); // <--- Look at this!
      self.list();
    });
  }

self.products.push(product); 在成功处理程序中正确更新我的产品可观察。然后,一个新行会自动添加到我的表中,这是个好消息。

坏消息是,一旦我将新产品推送到数组中,数据表控件(例如搜索字段或可点击的排序箭头)就会消失。为什么这样!?

4

2 回答 2

1

你有没有解决过这个问题?

我多年来一直有类似的问题。

最后,我的解决方法是使用 ko.mapping.fromJS(entity) 映射我的所有实体 - 然后连接所有必需的依赖项并确保任何更改都流经我的模型。

于 2013-12-13T13:17:02.753 回答
0

http://jsfiddle.net/zachpainter77/4tLabu56/

ko.bindingHandlers.DataTablesForEach = {

        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
             var nodes = Array.prototype.slice.call(element.childNodes, 0);
            ko.utils.arrayForEach(nodes, function (node) {
                if (node && node.nodeType !== 1) {
                    node.parentNode.removeChild(node);
                }
            });
            return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
        },
        update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

            var value = ko.unwrap(valueAccessor()),
            key = "DataTablesForEach_Initialized";

            var newValue = function () {
                return {
                    data: value.data || value,
                    beforeRenderAll: function (el, index, data) {

                        if (ko.utils.domData.get(element, key)) {

                            $(element).closest('table').DataTable().destroy();
                        }
                    },
                    afterRenderAll: function (el, index, data) {
                        $(element).closest('table').DataTable(value.options);
                    }

                };
            };

            ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, bindingContext);

            //if we have not previously marked this as initialized and there is currently items in the array, then cache on the element that it has been initialized
            if (!ko.utils.domData.get(element, key) && (value.data || value.length)) {
                ko.utils.domData.set(element, key, true);
            }

            return { controlsDescendantBindings: true };
        }
    };

https://rawgit.com/zachpainter77/zach-knockout.js/master/zach-knockout.debug.js

于 2015-08-10T18:39:30.237 回答