I've made a working Plunker to test things out.
I have a ng-repeat that is just listing names and id of kitties. I also have an input form to receive a name of a new kitty. Then, I have 3 buttons, each one accessing a different $scope function that will manipulate the $scope in different ways.
The goal of every function is to read the name of the kitty from the input form, read the last id used on the kitties array, assign that id+1 to the new kitty, push the new kitty to the array of kitties and delete the form data.
The first function, $scope.addFullScope()
,
will receive nothing as arguments and will read and manipulate everything from $scope
.
The second function, $scope.addJustDelete(kitty, kitties)
,
will receive both the new kitty
and the kitties
array as argument. But, on the end, to clean up the form, it will do $scope.kitty = undefined
The third function, $scope.addNoScope(kitty, kitties)
,
will receive both the new kitty
and the kitties
array as argument. But, on the end, to clean up the form, it will do kitty = undefined
. But the form won't clean up! and everything will star to bug out.
Appendix:
Html:
<body ng-app='app' ng-controller="ctrl">
<h3 ng-repeat="kitty in kitties">
{{kitty.name}}: {{kitty.id}} //Kitties list
</h3>
<input placeholder='Kitty name to add' class='form form-control'
type="text" ng-model="kitty.name" />
<h3> $scope use on adding kitty:</h3>
<button ng-click="addFullScope()">Full Scope.</button>
<button ng-click="addJustDelete(kitty, kitties)">Just delete.</button>
<button ng-click="addNoScope(kitty, kitties)">None. Buggy</button>
</body>
Controller:
.controller('ctrl', function($scope) {
$scope.kitties = [
//Let's imagine kitties in here.
{name: 'Purple kitty', id:35},
//Kittie 36 died in a car accident. :(
{name: 'Rodmentou cat', id: 37},
{name: 'Fatty kitty', id: 38}
];
$scope.addFullScope = function () {
var size = $scope.kitties.length;
var id = $scope.kitties[size-1].id + 1;
$scope.kitty.id = id;
$scope.kitties.push($scope.kitty);
$scope.kitty = undefined;
};
$scope.addJustDelete = function (kitty, kitties) {
var size = kitties.length;
var id = kitties[size-1].id + 1;
kitty.id = id;
kitties.push(kitty);
$scope.kitty= undefined;
};
$scope.addNoScope = function (kitty, kitties) {
var size = kitties.length;
var id = kitties[size-1].id + 1;
kitty.id = id;
kitties.push(kitty);
kitty = undefined; //Don't work
};
});
Under the hood Angular needs a way to watch if a ngModel is changed and uses $scope.$watch to accomplish this. $watch is considered a Equality Watcher, where it checks if one specific property has changed and not if the object underlying it has changed, which would be a Reference Watcher.
I found a good description and image of this on Tero Parviainen's blog
So the issue with your code is that you are setting kitty = undefined
, but ngModel and by extension $scope.$watch is looking for a change in kitty.name
. To prove this was the case I added a watch on kitty.name
and when you set kitty = undefined
the watch never gets triggered. Setting kitty to undefined changes the underlying object, but not it's properties (pretty confusing)! I created a plunker example with updated code.
HTML
For clarity sake, I made the model we are updating kitten
so it is not confused with the kitties
we are iterating over.
<h3 ng-repeat="kitty in kitties">
{{kitty.name}}: {{kitty.id}}
</h3>
<input placeholder='Kitty name to add' class='form form-control' type="text" ng-model="kitten.name" />
<h3> $scope use on adding kitty:</h3>
<button class='btn btn-success' ng-click="addNoScope(kitten, kitties)">None. Buggy</button>
<button class='btn btn-danger' ng-click="noWatch(kitten)">Full Scope.</button>
Javascript
The big update is creating a clone kitten out of the model's kitten, so that it is not referenced within the array. Also when we want to reset the model's kitten we set the kitten.name
and kitten.id
properties directly.
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.kitten = {
name: undefined, id: undefined
};
$scope.$watch('kitten.name', function() { console.log("changed"); }, true);
$scope.kitties = [
//Let's imagine kitties in here.
{name: 'Purple kitty', id:35},
//Kittie 36 died in a car accident. :(
{name: 'Rodmentou cat', id: 37},
{name: 'Fatty kitty', id: 38}
];
$scope.addNoScope = function (kitten, kitties) {
if (!$scope.kitten || !$scope.kitten.name) return;
var size = kitties.length;
var id = kitties[size-1].id + 1;
var newKitten = {
name: kitten.name, id: id
}
kitties.push(newKitten);
kitten.name = undefined;
kitten.id = undefined;
// kitten = undefined;
};
$scope.noWatch = function (kitten) {
kitten = undefined;
console.log('not watching');
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With