示例代码在这里。 https://jsfiddle.net/zLnuyk3w/4/
function ViewModel(){
var self = this;
var ids = [
{ id:50, order:1},
{ id:25, order:2},
{ id:35, order:3}
];
var list = ko.observableArray(ids);
self.sortedList = ko.observableArray();
ko.computed(function(){
var computedList = list().sort(function(l, r){
return l.order < r.order ? -1 : 1;
});
self.sortedList(computedList);
});
self.addNewItem = function(){
list.push({id: 40, order:2});
}
self.deleteItem = function(item){
list.remove(item);
}
}
var vm = new ViewModel();
ko.applyBindings(vm);
$('tbody').sortable({
update: function(event, ui) {
// vm.list().updateOrder(); // somehow update 'order' property but for simplicity reason, omit the actual code
vm.list.valueHasMutated();
}
});
$( "tbody" ).disableSelection();
我基本上想用jquery UI可排序插件手工排序一行表。但在手工排序并尝试从observableArray中删除项目后,删除无法正常工作。
我彻底搜索相关问题,似乎我可能需要在调用ko.cleanNode后重新绑定视图模型。这是解决这个问题的唯一方法吗?我实际上想要避免这种方法,因为我正在玩的数据是动态生成的,并且视图使用了很多模板,因此为重新绑定元素传递正确的数据非常复杂。
答案 0 :(得分:2)
问题比你想象的要简单,而不是淘汰相关:
对于具有相同0
索引的项目,您不会返回order
。将排序方法更改为:
return l.order === r.order ? 0 : l.order < r.order ? -1 : 1;
现在,在添加项目时,您的表格至少可以正确排序。如果要通过某种外部逻辑动态更改order
属性,则必须使它们observable
。你会离开这个:
self.sortedList = ko.pureComputed(function() {
return list().sort(function(l, r){
return l.order === r.order
? 0
: l.order < r.order ? -1 : 1;
});
});
对此:
self.sortedList = ko.pureComputed(function() {
return list().sort(function(l, r){
var oL = l.order(),
oR = r.order();
return oL === oR
? 0
: oL < oR ? -1 : 1;
});
});
现在,只要list
或其中一个项order
属性发生更改,列表就会重新排序。
如果这不起作用,或者不是你需要的,问题可能在jQuery小部件中。如果它从您的html中删除元素,则淘汰赛可能会失去其连接。 (例如,如果按克隆元素排序并重新排序)
您可以通过编写在update
函数中重新应用窗口小部件的自定义绑定处理程序,或者通过删除插件并使用我正在描述的系统来解决此问题。看看这个例子:
function ViewModel() {
var self = this;
var ids = [{
id: 50,
order: ko.observable(1)
}, {
id: 25,
order: ko.observable(2)
}, {
id: 35,
order: ko.observable(3)
}];
var list = ko.observableArray(ids);
self.sortedList = ko.observableArray();
ko.computed(function() {
var computedList = list().sort(function(l, r) {
var lO = l.order(),
rO = r.order();
return lO === rO ? 0 : lO < rO ? -1 : 1;
});
self.sortedList(computedList);
});
self.addNewItem = function() {
list.push({
id: 40,
order: 0
});
}
self.deleteItem = function(item) {
list.remove(item);
}
}
var vm = new ViewModel();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<table>
<tbody data-bind="foreach: sortedList">
<tr>
<td data-bind="text:id"></td>
<td>
<label>order:
<input type="number" data-bind="value: order">
</label>
</td>
</tr>
</tbody>
</table>
答案 1 :(得分:0)
正如托马拉克所说的那样,它比我想象的要复杂得多,他指出的自定义装订效果非常好 https://github.com/rniemeyer/knockout-sortable
我稍后会发布示例代码。
修改强>
我无法弄清楚如何将本地js文件添加到fiddler所以这次只是一个示例代码。请参考knockout-sortable.js,它会为您完成一项工作。在这种情况下,我不需要计算的observable,因为项目在列表中的位置实际上是由自定义绑定更改的,这就是我想要的。当然,如果您想要使用其他操作更改列表的顺序,则需要使用计算的observable进行排序。
<table>
<tbody data-bind="sortable: list" >
<tr>
<td data-bind="text:id"></td>
<td ><button data-bind="click:$root.deleteItem">
delete
</button></td>
</tr>
</tbody>
</table>
function ViewModel(){
var self = this;
var ids = [
{ id:50},
{ id:25},
{ id:35}
];
self.list = ko.observableArray(ids);
self.deleteItem = function(item){
self.list.remove(item);
}
}
ko.applyBindings(new ViewModel());