-->

AngularJS/ng-grid - Updating array with splice doe

2020-02-11 05:31发布

问题:

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!

回答1:

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



回答2:

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.



回答3:

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