2012-10-10 2 views
1

J'ai récemment utilisé une excellente réponse de débordement de pile par RP Niemeyer, KnockoutJS ObservableArray data grouping, pour me permettre de regrouper des données dans un observableArray par un champ. Cela fonctionne brillamment. Le problème est qu'il ne joue pas bien avec Knockout Sortable. Il y a un problème avec la récupération du sourceParent. S'il vous plaît voir le violon suivant: http://jsfiddle.net/mrfunnel/g6rbcKnockoutJS Groupe triable observableArray par champ et tri par condition

Fondamentalement, j'ai une liste imbriquée où les tâches sont regroupées en routes (non programmées) et une autre liste de tâches juste (planifiée). Je veux être capable de faire glisser des routes et des tâches dans le calendrier. Si un itinéraire est déplacé, il doit se diviser en tâches.

Toute aide serait grandement appréciée.

Répondre

6

La liaison sortable ne fonctionne que contre observableArrays, car elle doit savoir comment réécrire la valeur supprimée dans le tableau. Avec le résultat d'une observable calculée, il ne serait pas capable de l'écrire de manière significative.

Voici une autre façon de structurer votre code. Fondamentalement, vous construiriez un observableArray de routes qui contiennent chacune un observableArray de tâches. Quelque chose comme:

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

}); 

Ensuite, vous pouvez utiliser la fonction de rappel beforeMove sur vos tâches planifiées pour vérifier si elle est une route plutôt que d'une tâche individuelle et faire la séparation comme:

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

Voici un échantillon mis à jour: http://jsfiddle.net/rniemeyer/BeZ2c/. Je ne suis pas sûr si vous permettez le tri entre les itinéraires, mais j'ai désactivé cela dans l'échantillon. Vous pouvez déposer des tâches individuelles ou des itinéraires entiers dans les tâches planifiées.

+0

Bonne réponse. J'aime knock-out de plus en plus. Merci beaucoup. – TheGwa

Questions connexes