How do you keep the DOM and the model in sync when using nested JQuery sortables? Say I have a Controller which is has defined as follows:
function testCtrl($scope) {
$scope.data = [{'name' : 'Test 1',
'index' : 0,
'values': [{'name' : 'sub test 1-1', 'index' : 0}, {'name' : 'sub test 1-2', 'index' : 1}]},
{'name' : 'Test 2',
'index' : 1,
'values': [{'name' : 'sub test 2-1', 'index' : 0}, {'name' : 'sub test 2-2', 'index' : 1}]}
];
$scope.orderProp = 'index';
}
Now I want to show the first level data and the second level data in JQuery sortables using the following template :
<ul ng-sortable='data'>
<li ng-repeat="d in data | orderBy:orderProp">
<p>{{d.name}}</p>
<ul ng-Sub-Sortable="d.values">
<li ng-repeat="sub in d.values">{{sub.eg}}</li>
</ul>
</li>
</ul>
And I use directives to specify the two different types of sortable lists as they do differ in behaviour (removed from below for brevity):
app.directive("ngSortable", function(){
return {
link: function(scope, element, attrs){
element.sortable();
}
};
}
app.directive("ngSubSortable", function(){
return {
link: function(scope, element, attrs){
element.sortable();
}
};
}
Now when the user sorts the list how do I update the model to ensure that the indexes are correct and therefore the lists are output correctly in the future?
You'd better use ngModel to sync data with dom
You could try this one: https://github.com/JimLiu/Angular-NestedSortable
The best method I have found for keeping the model in sync with the DOM for items with position dependant data in a nested sortable is to add the current position to each element as an attribute as follows :
<ul ng-sortable='data'>
<li ng-sortable-index="{{$index}}" ng-repeat="d in data | orderBy:orderProp">
<p>{{d.name}}</p>
<ul ng-Sub-Sortable="d.values">
<li ng-sortable-index="{{$index}}" ng-repeat="sub in d.values">{{sub.eg}}</li>
</ul>
</li>
Then in the directives where the jQuery sortable is initialised the sortable update method should be specified as follows :
element.sortable({
update: function(event, ui) {
var model = scope.$eval(attrs.ngSubSortable);
// loop through items in new order
element.children().each(function(index) {
// get old item index
var oldIndex = parseInt($(this).attr("ng-sortable-index"), 10);
model[oldIndex].index = index;
});
scope.$apply();
}
});