Javascript KnockoutJS可排序组ObservalArray按字段和条件排序

Javascript KnockoutJS可排序组ObservalArray按字段和条件排序,javascript,jquery,knockout.js,jquery-ui-sortable,Javascript,Jquery,Knockout.js,Jquery Ui Sortable,我最近使用了RP Niemeyer的一个很好的堆栈溢出答案,允许我按字段将数据分组到一个可观察的数组中。这是非常出色的工作。问题是它没有很好地发挥作用。检索sourceParent时出现问题。请看下面的小提琴: 基本上,我有一个嵌套列表,其中任务被分组为路由(未计划)和另一个仅任务列表(已计划)。我希望能够将路线和任务拖到计划中。如果拖入路线,则需要将其拆分为多个任务 任何帮助都将不胜感激。可排序的绑定只对ObservalArray有效,因为它需要知道如何将删除的值写回数组。有了计算出的可观测结

我最近使用了RP Niemeyer的一个很好的堆栈溢出答案,允许我按字段将数据分组到一个可观察的数组中。这是非常出色的工作。问题是它没有很好地发挥作用。检索sourceParent时出现问题。请看下面的小提琴:

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


任何帮助都将不胜感激。

可排序的绑定只对ObservalArray有效,因为它需要知道如何将删除的值写回数组。有了计算出的可观测结果,它将无法以有意义的方式写入它

下面是另一种方法,您可以用它来构造代码。基本上,您将构建一个路由的ObservalArray,每个路由都包含一个任务的ObservalArray。比如:

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);                
    }
};

以下是更新的示例:。我不确定您是否允许在路由之间进行排序,但我在示例中禁用了该选项。您可以将单个任务或整个路由拖放到计划任务中。

可排序的绑定仅适用于ObservalArrays,因为它需要知道如何将拖放的值写回数组。有了计算出的可观测结果,它将无法以有意义的方式写入它

下面是另一种方法,您可以用它来构造代码。基本上,您将构建一个路由的ObservalArray,每个路由都包含一个任务的ObservalArray。比如:

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);                
    }
};

以下是更新的示例:。我不确定您是否允许在路由之间进行排序,但我在示例中禁用了该选项。您可以将单个任务或整个路线放入计划任务中。

回答得很好。我越来越喜欢击倒。非常感谢,回答得很好。我越来越喜欢击倒。非常感谢你。