-->

Scope confusion in ng-grid when returning data fro

2019-02-26 11:11发布

问题:

Here is the Plunker: http://plnkr.co/edit/aqLnno?p=preview

I have a list of persons ($scope.persons) to be displayed in a ng-grid. Each line has a edit button. When the user clicks on the button (ng-click="edit(row)") (see code below), I copy the displayed person (angular.copy(row.entity)) and open a modal dialog. ... so far so good.

When the user clicks "Cancel" on the modal, nothing happens. When the user clicks "Save" on the model, the modified person is returned and should be "reintegrated" in $scope.persons.

This is where the problem starts: I search in $scope.persons to find the correct person and replace it with the person returned from the modal. The log statements show the $scope.persons before and after the modification and everything looks good. However, the ng-grid doesn't seem to care. It still operates on a different (the old) $scope.persons.

If I uncomment the row.entity = person and set the row directly, everything looks fine in the ng-grid. However, as the underlying data model is not changed correctly, a resort will bring up the old (un-modified) person again.

Here is the code of my edit function:

$scope.edit = function(row) {
  $modal.open({
    templateUrl: 'personEdit.html',
    backdrop: true,
    windowClass: 'modal',
    controller: 'PersonModalInstanceCtrl',
    resolve: {
      person: function() {
        return angular.copy(row.entity);
      }
    }
  })
    .result.then(function(person) {
      $log.log('Edited person: ' + JSON.stringify(person));
      angular.forEach($scope.persons, function(p, index) {
        $log.log('p: ' + JSON.stringify(p) + ' index: ' + index);
        if (p.id == row.entity.id) {
          $log.log('scope: ' + JSON.stringify($scope.persons));
          $scope.persons[index] = person;
        }
      });
      $log.log('scope: ' + JSON.stringify($scope.persons));
      // row.entity = person;
    }, function() {});
};

What am I doing wrong with my scopes?

Thanks for any help

回答1:

OK. Again something learnt. The answer of jantimon pointed me in the right direction. But I didn't like how he changed my $scope.persons array (I get this array from a RESTful GET and liked the fact that I can just use the returned JSON as $scope.persons without modification).

Anyway, here is the explanation:

When copying my person from the original $scope.persons list I created a new object in a new memory location:

angular.copy(row.entity)

This is necessary as the user can "Cancel" his edit.

When the user clicks "Save" I have to take this copied person and put it back to $scope.persons instead of the old one. I did this with:

$scope.persons[index] = person;

Although this is correct and gives the desired result (as the log statements show), the persons[index] now points to a different memory location.

BUT: ng-grid internally still points to the old memory location! ng-grid has not memorized the pointer (person[index]) as the data model but instead has memorized the destination of the original pointer (*person[index]) [sorry for my C-stylish talking]. I would consider this a BUG in ng-grid IMHO.

So all I need to do is copy the new person back to the exact same memory location it has come from. Luckily, there is an angular directive for that:

angular.extend($scope.persons[index], person);

If you just replace $scope.persons[index] = person; with angular.extend($scope.persons[index], person); everything works fine.



回答2:

Looks like ng-grid isn't updating correctly when you are changing the array

You might keep the pointer of the row entity like in this example here: http://plnkr.co/edit/0lDoKOg4kXXa51NlSuMg?p=preview

It uses $scope.persons[index].data = person.data; instead of $scope.persons[index] = person;.