Bastien Caudan
Bastien Caudan

Reputation: 4490

Migration to AngularJS 1.2 breaks sortable-wrapper directive

I have a sortable-wrapper directive that allow moving an item inside a list and from a list to another.

With an array container:

$scope.container = [
  [{id: '1.1'}, {id: '1.2'}, {id: '1.3'}],
  [{id: '2.1'}, {id: '2.2'}, {id: '2.3'}]
]

I use the directive like this:

<div ng-repeat="array in container">
  <ul sortable>
    <li ng-repeat="item in array">{{ item.id }}</li>
  </ul> 
</div>

When an item is dropped into a list, I have to update items backend side and insert the moved item that is returned by the backend at the right array/index:

$scope.move = function (from, fromIndex, to, toIndex) {
  $http.post(url, data).success(function(movedItem) {
    from.splice(fromIndex, 1)[0];
    to.splice(toIndex, 0, movedItem);
  });
} 

This directive was working well until the version 1.2.0-rc.2, since 1.2.0-rc.3 I get this error when moving an item :

TypeError: Cannot call method 'insertBefore' of null
    at http://code.angularjs.org/1.2.1/angular.js:3857:22
    at forEach (http://code.angularjs.org/1.2.1/angular.js:303:18)
    at Object.enter (http://code.angularjs.org/1.2.1/angular.js:3856:9)
    at http://code.angularjs.org/1.2.1/angular.js:18828:26
    at publicLinkFn (http://code.angularjs.org/1.2.1/angular.js:5443:29)
    at boundTranscludeFn (http://code.angularjs.org/1.2.1/angular.js:5555:21)
    at controllersBoundTransclude (http://code.angularjs.org/1.2.1/angular.js:6145:18)
    at ngRepeatAction (http://code.angularjs.org/1.2.1/angular.js:18826:15)
    at Object.$watchCollectionAction [as fn] (http://code.angularjs.org/1.2.1/angular.js:11347:11)
    at Scope.$digest (http://code.angularjs.org/1.2.1/angular.js:11443:27) 

Here is a plunker that reproduce the error: http://plnkr.co/edit/bAD8z2KdW34a7hkhdyiu?p=preview

Any thought ?

Upvotes: 0

Views: 758

Answers (2)

Bastien Caudan
Bastien Caudan

Reputation: 4490

Finally, I change my implementation to use the angular-ui ui-sortable module. The angular 1.2 branch takes into account the changes of 1.2 version of the ng-repeat directive. See the pull request.

Upvotes: 0

Nikos Paraskevopoulos
Nikos Paraskevopoulos

Reputation: 40296

Use this:

<li ng-repeat="item in array track by item.id">{{ item.id }}</li>

Why?

I think you are creating items anew (getNewItemFromBackend(item)) once their position is changed. Because ngRepeat is tracking them by object equality, once an object leaves the list, Angular cannot find it to insert the DOM element. I am not 100% satisfied with this explanation, but it is roughly what is going on.

Upvotes: 1

Related Questions