angularjshtml-tableangularjs-ng-repeateditdirty-data

How to get back to previous state of a model making it dirty using cancel button


I have this plunkr here, which displays an editable table.

Following is the HTML code for table:

  <body ng-controller="MainCtrl">
    <table style="width:100%">
  <tr>
    <th>Name</th>
    <th>Is enabled?</th>        
    <th>Points</th>
  </tr>
  <tr ng-repeat="fooObject in fooObjects | orderBy:'points'">
    <td><input ng-model="fooObject.name" ng-disabled="fooState!='EDIT'"/></td>
    <td><input ng-model="fooObject.isEnabled" ng-disabled="fooState!='EDIT'"/></td>     
    <td><input ng-model="fooObject.points" ng-disabled="fooState!='EDIT'"/></td>
    <td>
      <a href="#" ng-click="handleEdit(fooObject, 'EDIT', $index)">Edit</a>
      <a href="#" ng-click="handleEditCancel(fooObject, 'VIEW', $index)">Cancel</a>
    </td>
  </tr>
</table>
  </body>

I would like the Cancel link in the row display the previous state of the fooObject as if that row was never touched.

Following is the code in the AngularJS controller, which seems to work as long as I don't have "orderBy:'points'" in the ng-repeat expression, but doesn't work otherwise:

app.controller('MainCtrl', function($scope) {
  $scope.fooObjects = [
    {"name": "mariofoo", "points": 65, "isEnabled": true}, 
    {"name": "supermanfoo", "points": 47, "isEnabled": false}, 
    {"name": "monsterfoo", "points": 85, "isEnabled": true}
    ];

    $scope.fooState = 'VIEW';

    $scope.originalFooObject = null;
    $scope.handleEdit = function(fooObject, fooState, index){
       $scope.originalFooObject = angular.copy(fooObject);
       $scope.fooObject = fooObject;
       $scope.fooState = fooState;
    }

    $scope.handleEditCancel=function(fooObject, fooState, index){
      $scope.fooObjects[index] = $scope.originalFooObject;
       $scope.originalFooObject=null;
       $scope.fooState = fooState;
    }


});

Could somebody help me understand how get it resolved?


Solution

  • You were right to use master/copy of the object. But you restore the original value out of context of your editable row. And so, it doesn't work with orderBy because orderBy changes the index and you end up updating (rather than resetting) a different element. But it wouldn't work even without 'orderBy': try edit one row but hitting cancel on another. Do you see why it doesn't work?

    There are a number of ways to do this. For example, your fooObjects can contain the copy of each row under edit:

    $scope.handleEdit = function(fooObject){
      fooObject.$original = fooObject.$original || angular.copy(fooObject);
      $scope.fooState = "EDIT";
    }
    
    $scope.handleEditCancel = function(fooObject){
       angular.copy(fooObject.$original, fooObject);
       $scope.fooState = "VIEW";
    }
    

    (notice how you don't need index)

    Here's your updated plunker