@{ var initialData = new JavaScriptSerializer().Serialize(Model); } var data = @Html.Raw(initialData); function viewmodel(data) { var self = this; self.Name = ko.observable(data.Name); self.Items = ko.observableArray(data.Items); self.addItem = function() { self.Items.push(""); }; self.removeItem = function(data) { self.Items.remove(data); } } $(document).ready(function() {ko.applyBindings(new viewmodel(data)); });
以下视图:
<div> Name: <span data-bind="text: Name"></span> </div> <div> Items: <button data-bind="click: addItem">Add Item</button> </div> <div> <table> <tbody data-bind="template: { name: 'itemTemplate',foreach: Items }"></tbody> </table> </div> <script type="text/html" id="itemTemplate"> <tr> <td> <input data-bind="value: $data" /> <a href="#" data-bind="click: function() {$parent.removeItem($data)}">Remove Item</a> </td> </tr> </script>
除了removeItem之外,一切似乎都能正常工作.添加新行并在空的新行上单击“删除项”时,将删除所有新行.我看了很多淘汰教程试图让这个工作,我的方法似乎是一个有效的尝试,但显然……我必须遗漏一些东西.有什么建议?
解决方法
有几种方法可以处理它:
>你可以处理对象而不仅仅是{value:ko.observable(“”)}之类的字符串.然后,当您传递$data时,它将仅删除与该对象引用匹配的实际项.如果您的值不可观察并且是数据本身(而不是属性),那么您的写入实际上不会使其返回到您的视图模型.
>如果这对您的方案不起作用,那么您可以使用splice删除基于索引($index)的项目.
我可能会这样做:http://jsfiddle.net/rniemeyer/N3JaW/
另请注意,事件(单击是事件包装器)绑定会将当前数据作为处理程序的第一个参数传递,因此您可以简化绑定以单击:$parent.removeItem.
更新:您可以通过以下几种方法控制对象转换为JSON的方式:
> ko.toJSON将其第二个和第三个参数传递给JSON.stringify.第二个arg让你运行一个函数来替换here所描述的值.下面是一个示例,它检查键是否是一个数字(数组项)并且它有一个value属性.如果是这样,它只返回字符串而不是对象. http://jsfiddle.net/rniemeyer/N3JaW/1/
>如果对对象使用构造函数,则可以如here所述覆盖toJSON函数.以下是具有此功能的示例:http://jsfiddle.net/rniemeyer/N3JaW/2/
>可以使用的另一种技术是维护具有“良好”值的计算可观察量.下面是示例:http://jsfiddle.net/rniemeyer/N3JaW/3/.在这一个中,Items是一个计算的observable,它返回clean值. Items.asObjects包含值的对象版本.转换为JSON时,当Items转换为JSON时,asObjects部分自然会被删除.如果在转换为JSON时只需要这个“好”数组,那么其他选项对于性能更好(它们仅在您想要发送时计算).