KnockoutJS可排序组observableArray by field和conditionally sort

时间:2012-10-10 15:26:04

标签: javascript jquery knockout.js jquery-ui-sortable

我最近使用了RP Niemeyer KnockoutJS ObservableArray data grouping的一个很好的堆栈溢出答案,允许我通过字段对observableArray中的数据进行分组。这工作非常出色。问题是它与Knockout Sortable的效果不佳。检索sourceParent存在问题。请参阅以下小提琴:http://jsfiddle.net/mrfunnel/g6rbc

基本上我有一个嵌套列表,其中任务被分组为路由(未预定)和另一个任务列表(预定)。我希望能够将路线和任务拖到预定的位置。如果拖入路线,则需要将其拆分为任务。

非常感谢任何协助。

1 个答案:

答案 0 :(得分:6)

sortable绑定仅适用于observableArrays,因为它需要知道如何将删除的值写回数组。使用计算的observable的结果,它将无法以有意义的方式编写它。

以下是您可以构建代码的另一种方法。基本上,您将构建一个observableArray路由,每个路由都包含一个observableArray任务。类似的东西:

self.tasks.subscribe(function(tasks) {
    var routes = [],
        routeIndex = {};

    ko.utils.arrayForEach(tasks || [], function(task) {
       var routeId = task.routeId(),
           routeTasks = routeIndex[routeId];

       //first time that we have seen this routeID
       if (!routeTasks) {
           //add it to the index, so we can find it without looping next time 
           routeIndex[routeId] = routeTasks = { id: routeId, tasks: ko.observableArray() };
           //add it to the array that we will eventually return
           routes.push(routeTasks);
       }

       routeTasks.tasks.push(task);
    });

    //return an array of routes that each contain an array of tasks
    self.tasksByRoute(routes);       

});

然后,您可以对计划任务使用beforeMove回调来检查它是否是路线而不是单个任务,并执行拆分,如:

self.myDropCallback = function(arg) {
    var spliceArgs;
    //determine if this is really a route rather than an individual task
    if (arg.item && arg.item.tasks) {
       //we will handle the drop ourselves, since we have to split into tasks
       arg.cancelDrop = true;

        //build up args, since first two need to be new index and items to remove
       spliceArgs = [arg.targetIndex, null];
       //add the tasks to the args
       spliceArgs.push.apply(spliceArgs, arg.item.tasks());
       //splice in the tasks at the right index
       arg.targetParent.splice.apply(arg.targetParent, spliceArgs); 

       //remove the originals, after cancel has happened
       setTimeout(function() {
          arg.sourceParent.remove(arg.item);    
       }, 0);                
    }
};

以下是更新后的示例:http://jsfiddle.net/rniemeyer/BeZ2c/。我不确定您是否允许在路由之间进行排序,但我在示例中禁用了它。您可以将单个任务或整个路径放入计划任务中。