Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ng-repeat not updating with array changes

I have looked over this issue for many hours and read many other questions that seem entirely the same and I have tried every one of their solutions, but none seem to work.

I have an array of objects (instructionObj.instructions) and those objects get repeated with ng-repeat and their template is a directive.

<div instruction-directive ng-repeat="i in instructionsObj.instructions"> </div>

I then allow the items to be sorted using Jquery UI sortable.

var first, second;
$( ".sort" ).sortable({
  axis: "y",
  start: function( event, ui ) {
      first = ui.item.index();
  },
  stop: function( event, ui ) {
      second = ui.item.index();
      console.log(first + " " + second);
      rearrange(first, second);
      $scope.$apply();
  }
});

I then access the start and end index of the object being moved and rearrange the array accordingly:

function rearrange(f, s){
    $timeout(function () {
        $scope.instructionsObj.instructions.splice(s, 0,
            $scope.instructionsObj.instructions.splice(f, 1)[0]);
        $scope.$apply();
    });
}

All of this works great most of the time. The one scenario I have found a failure is when rearranging the objects as such (one column is the current position of all objects displayed on the screen):

a | b | c | d | a

b | c | d | c | b

c | d | b | b | d

d | a | a | a | c

The last step should be a, d, c, b. But it changes to a, b, d, c.

wrong configuration

However, when I go back to my previous view and come back the correct configuration is displayed, all is well. As you can see I have tried $timeout and $apply() and many other things, but none seem to work.

I know this is a DOM updating issue because I can log the array and see that it is different (correct) from what the DOM shows (incorrect). Any help would be appreciated.

Update:

I am even using <pre ng-bind="instructionsObj.instructions|json</pre> to show the exact layout of the array and it is always correct. My mind is blown.

like image 555
theblindprophet Avatar asked Nov 08 '22 16:11

theblindprophet


1 Answers

Fortunately I have found a solution, even though I do not understand why the problem was happening anyway.

In this JS:

sortableEle = $('.sort').sortable({
    start: $scope.dragStart,
    update: $scope.dragEnd
});

$scope.dragStart = function(e, ui) {
    ui.item.data('start', ui.item.index());
}
$scope.dragEnd = function(e, ui) {
    var start = ui.item.data('start'),
        end = ui.item.index();

    $scope.instructionsObj.instructions.splice(end, 0,
        $scope.instructionsObj.instructions.splice(start, 1)[0]);
    currentRecipe.setInstructions($scope.instructionsObj.instructions);
    $scope.$apply();
    sortableEle.refresh();
}

I needed to call $scope.$apply() as well as sortableEle.refresh() after altering the array.

Again, I do not understand why it would mess up 10% of the time, but that fixed it.

FYI: I changed up the sortable function a little, but it does the same exact thing as before.

like image 193
theblindprophet Avatar answered Nov 14 '22 21:11

theblindprophet