AngularJS/ng-grid - Updating array with splice doesn't updates UI
Asked Answered
C

3

7

I am trying to update ng-grid with array splice. I have a plunk here.

Add button adds new row. Update button updates last item in the array.

  1. Select a row & press update button. Nothing happens.
  2. Press add button. Now UI gets updated with new element & as well as the previously updated element.
  3. Same behavior gets repeated again & again.

I tried $scope.$apply. I get:

“Error: $apply already in progress”

I even tried by placing $scope.$apply block inside a setTimeout call. Again the same error!

Any pointers!

Thanks!

Chaing answered 8/7, 2013 at 14:45 Comment(0)
T
15

That's because data $watcher in ng-grid (incorrectly) compares the data object for reference, instead on object equality. You might remedy this by setting the third parameter to true in data $watch function (line 3128):

$scope.$parent.$watch(options.data, dataWatcher, true);

Plunker

Trogon answered 9/7, 2013 at 9:48 Comment(4)
I'd give you 100 points if I could... this killed me when updating my remote data source.Pineal
It wasn't obvious to me where to put the code in this question; so I just wanted to add that it was a mod to the grid.js file.Freedom
Do you know if this is fixed in the new version of ng-grid? I think I have a very similar problem.Severin
I gave up on ngGrid. Consider trying Smart Table.Trogon
A
4

UPDATE (2015-04-10)

Angular has improved their code base (1.4.0), try the $scope.$watchCollection method first, and see if it works for you. (Link)

ANSWER

If you don't feel like hacking into a 3rd party library, you could add the hack in your code using:

$scope.updateData = function() {
  var data = angular.copy($scope.myData);
  data.splice(data.length - 1, 1, {name: 'UPDATED', age: '4'})
  $scope.myData = data;
};

plunkr

As @Stewie mentions, the problem is that for performance reasons ngGrid compares the data object superficially, and in the case of arrays, this is by reference. ngGrid also compares by the array length, so if the array doesn't change it's length the grid wont' get updated.

This solution creates a copy of the array (different place in memory) so that when angularjs $watcher checks for changes it will find a different object and run the ngGrid update callback.

NOTE: Because this solution creates a copy of the data array on every call to updateData, it could lead to performance problems if your data is too big, also Javascript doesn't have a great garbage collection.

Old Incorrect Answer:

$timeout(angular.noop, 0);

This simply sets a timeout to trigger a $scope.$apply() after the current one is done. A way of forcing a dirty check.

Armil answered 15/2, 2014 at 7:12 Comment(2)
Can you get a Plunkr of this working? It's not working for me.Conscious
@Alain, you are right the $timeout answer doesn't work. It worked for me, but because I was in a different situation. I have updated my answer with a valid solution.Armil
A
0

I am using ui-grid v3.0.0 (from an April 2015 unstable build). I found this post and wanted to show others how I refreshed my grid after I removed a row from the grid data object using splice:

// Remove the row and refresh the grid.
$scope.myData.splice(rowIndex, 1);
$scope.gridApi.grid.refresh(true);

where my gridApi scope variable was set with this function:

$scope.gridOptions.onRegisterApi = function(gridApi){
    $scope.gridApi = gridApi;
}
Awestricken answered 22/4, 2015 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.