35

I'm simply try to reset values like this :

$scope.initial = [
    {
        data1: 10,
        data2: 20
    }            
];


$scope.datas= $scope.initial;


$scope.reset = function(){
  $scope.datas = $scope.initial;  
}

But it doesn't produce anything, any idea to fix it ?

angular.module('app', []).controller('MyCtrl', function($scope) {
  $scope.initial = [
    {
      data1: 10,
      data2: 20
    }            
  ];

  $scope.datas= $scope.initial;

  $scope.reset = function(){
    $scope.datas = $scope.initial;  
  } 
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MyCtrl">
  <div ng-repeat="data in datas">
    <input type="text" ng-model="data.data1" />
    <input type="text" ng-model="data.data2" />
  </div>
  <a ng-click="reset()">Reset to initial value</a>
  or     
  <button ng-click="name = initial">Reset to initial value</button>
  <hr />
  <p ng-repeat="data in datas">{{data.data1}}, {{data.data2}}</p>
</div>

There is a working example on jsfiddle

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Awea
  • 3,163
  • 8
  • 40
  • 59

7 Answers7

56

This is really a question about JavaScript (so I added the "javascript" tag). When a JavaScript object (such as array $scope.initial) is assigned to a variable, it is assigned by reference, not by copy. So, this statement

$scope.datas= $scope.initial;

results in $scope.datas pointing to the $scope.initial object. Any changes that are made to $scope.datas or $scope.initial both affect the same (single) object. Since ng-model is used to data-bind object elements data1 and data2, any changes to the text inputs will change the data1 and data2 elements of the object that $scope.datas references -- i.e., $scope.initial. To see this in action, add the following to your fiddle's HTML:

<p>{{initial}}</p>

When you change the values in the text boxes, you'll see that $scope.initial is also changing.

@Max provided a partial answer: use angular.copy() in the reset function. However, you'll also have to use angular.copy() in the initial assignment too:

 $scope.datas = angular.copy($scope.initial);

Update:

As @EpokK shows in his answer, an alternate solution is

angular.copy($scope.initial, $scope.datas);

As @bekite mentions in his answer, @EpokK's solution does not create another object.

The full code

angular.module('app', []).controller('MyCtrl', function($scope) {
  $scope.initial = [{
    data1: 10,
    data2: 20
  }];
  $scope.datas = angular.copy($scope.initial);
  $scope.reset = function () {
    $scope.datas = angular.copy($scope.initial);
    // or
    // angular.copy($scope.initial, $scope.datas);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" ng-controller="MyCtrl">
  <div ng-repeat="data in datas">
    <input type="text" ng-model="data.data1" />
    <input type="text" ng-model="data.data2" />
  </div> 
  <a ng-click="reset()">Reset to initial value</a>
  or
  <hr />
  <p ng-repeat="data in datas">{{data.data1}}, {{data.data2}}</p>{{initial}}
</div>

fiddle

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Thanks for you complete answer :) – Awea Oct 27 '12 at 11:00
  • 1
    **Hint**: For use in collections, the "alternate syntax" is preferable. It makes sure that the destination keeps Angular properties like $$hashKey intact. See this [plunk](http://plnkr.co/edit/T4yNXac0MWx7ndb0mI4c?p=preview) for a demonstration – martinczerwi Jan 28 '14 at 11:48
  • 1
    Here is the link to the official angular documentation including a working example: https://docs.angularjs.org/api/ng/function/angular.copy – Bijan Sep 26 '14 at 06:05
  • If you have a fairly large data object that can be _safely_ stringified and parsed to/from JSON (ie, attribute-value pairs, no functions), consider using something like `$scope.initial = JSON.parse(JSON.stringify($scope.datas));` as a faster clone. While `angular.copy` is far more robust, with large data sets it can chew up ms. – JcT Jul 07 '15 at 14:21
13

Try changing the reset function to use angular.copy

$scope.reset = function () {
    $scope.datas = angular.copy($scope.initial);
};
Max
  • 8,671
  • 4
  • 33
  • 46
11

@Mark Rajcok: Don't get me wrong, but I think that

angular.copy($scope.initial, $scope.datas);

is not an alternate syntax for

$scope.datas = angular.copy($scope.initial);

The way i understand it:

$scope.datas = angular.copy($scope.initial);

Creates a copy of $scope.initial and assigns the reference to $scope.datas.

angular.copy($scope.initial, $scope.datas);

Updates $scope.datas values with $scope.initial values

See the angularjs docs ( http://docs.angularjs.org/api/angular.copy ),and there the sektion on the Return statement

Returns The copy or updated destination, if destination was specified.

bekite
  • 3,444
  • 2
  • 23
  • 31
8

Working syntax :

$scope.reset = function () {
    angular.copy($scope.initial, $scope.datas);
};

API Reference : angular.copy(source[, destination]);

EpokK
  • 38,062
  • 9
  • 61
  • 69
  • 1
    Either syntax works in this case: `angular.copy(source, destination)` or `destination = angular.copy(source)` – Mark Rajcok Jul 10 '13 at 13:09
4

Consider the following buttons

  • Edit
  • Save
  • Cancel

When user clicks edit and changes data and then uses the cancel button to get the old data, here is how you could implement this.

HTML

<div>
    <button data-ng-click="edit()" data-ng-show="!editing">Edit</button>
    <button data-ng-click="save()" data-ng-show="editing">Save</button>
    <button data-ng-click="cancel()" data-ng-show="editing">Cancel</button>
</div>

AngularJs

$scope.edit = function () {
    $scope.editing = true;
    $scope.copy = angular.copy($scope.data);
};

$scope.cancel = function () {
    $scope.editing = false;
    $scope.data = $scope.copy;
};

References

Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
0

I love Yasser's comment: clear and concise.

I definitely prefer copying the value when starting to edit, and then just replacing the reference on cancel/save.

I prefer binding on a local copy, and not the original data, and then changing the final data only on save. This prevent all sorts of bugs later, and encapsulates the edit behavior.

The final version would be:

function initValue() {
    $scope.bound = angular.copy($scope.data);
}

function setValue() {
    $scope.data = $scope.bound;
}

$scope.edit = function () {
    $scope.editing = true;
    initValue();
};

$scope.cancel = function () {
    $scope.editing = false;
    initValue();
};

$scope.save= function () {
    $scope.editing = false;
    setValue();
};
Danny R
  • 13,734
  • 1
  • 15
  • 12
0

I have used as you all said above by maintaining a back up but while using it I faced one more problem.
I thought if i post it here it would be helpful to others

I have profile section code as below:

var profileBackup ={};
$scope.profileContinue = function()
{
  profileBackup = angular.copy($scope.userData.profile); 
//  profileBackup = $scope.userData.profile; 
//other code
}

$scope.profileCancel = function()
{
$scope.userData.profile = profileBackup;
}

But I was surprised to see that even non-scope variable profileBackup was updating when the model changes (I guess reference is returned in this case)

Then I changed my code like this:

$scope.profileContinue = function()
{
  profileBackup = angular.toJson($scope.userData.profile); 
//  profileBackup = $scope.userData.profile; 
//other code
}

$scope.profileCancel = function()
{
$scope.userData.profile = angular.fromJson(profileBackup);
}

please forgive me if it doesn't make any sense..