KnockoutJS Sortable group observableArray by field and conditionally sort

心已入冬 提交于 2019-12-08 03:56:42

问题


I have recently used a great stack overflow answer by RP Niemeyer, KnockoutJS ObservableArray data grouping, to allow me to group data in an observableArray by a field. That is working brilliantly. The problem is it is not playing nicely with Knockout Sortable. There is a problem with retrieving the sourceParent. Please see the following fiddle: http://jsfiddle.net/mrfunnel/g6rbc

Basically I have one nested list where tasks are grouped into routes (unscheduled) and another list of just tasks (scheduled). I want to be able to drag routes and tasks into scheduled. If a route is dragged in it needs to split up into tasks.

Any assistance would be greatly appreciated.


回答1:


The sortable binding only works against observableArrays, because it needs to know how to write the dropped value back to the array. With the result of a computed observable, it would not be able to write it in a meaningful way.

Here is an alternative way that you might be able to structure your code. Basically, you would build an observableArray of routes that each contain an observableArray of tasks. Something like:

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

});

Then, you can use the beforeMove callback on your scheduled tasks to check if it is a route rather than an individual task and do the splitting like:

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

Here is an updated sample: http://jsfiddle.net/rniemeyer/BeZ2c/. I am not sure if you allow sorting between the routes, but I disabled that in the sample. You can drop individual tasks or entire routes into the scheduled tasks.



来源:https://stackoverflow.com/questions/12822961/knockoutjs-sortable-group-observablearray-by-field-and-conditionally-sort

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!