I'm creating a form in HTML using ng-repeat to generate the form elements from an object in the scope. I also use that object to generate other elements outside of the ng-repeat.
A simplified example looks like this in HTML:
<div ng-app="App">
<div ng-controller="Ctrl">
<div class="block1">
<form ng-repeat="(key, value) in test">
<label>{{key}}</label>
<input ng-model="value" />
<p>{{value}}</p>
</form>
</div>
<div class="block2">
<p>
{{test.a}}
</p>
<p>
{{test.b}}
</p>
</div>
</div>
</div>
and this in JS:
angular.module('App', []);
function Ctrl($scope) {
$scope.test = {
a:"abc",
b:"def"
}
}
In this example, the text in block2 is set to the initial values of test.a
and test.b
. The input values and <p>
values inside of the loop are also set to the initial value.
When I modify the values within the inputs, the <p>
values inside of the ng-repeat block update correctly, but the <p>
tags in block2 fail to update.
Why is this the behavior? Does ng-repeat create its own isolated scope? If so how can I get the controller level scope to update? Also, could somebody explain the thinking behind this behavior and any advantages it provides?
JSFiddle Showing the problem
I'm creating a form in HTML using ng-repeat to generate the form elements from an object in the scope. I also use that object to generate other elements outside of the ng-repeat.
A simplified example looks like this in HTML:
<div ng-app="App">
<div ng-controller="Ctrl">
<div class="block1">
<form ng-repeat="(key, value) in test">
<label>{{key}}</label>
<input ng-model="value" />
<p>{{value}}</p>
</form>
</div>
<div class="block2">
<p>
{{test.a}}
</p>
<p>
{{test.b}}
</p>
</div>
</div>
</div>
and this in JS:
angular.module('App', []);
function Ctrl($scope) {
$scope.test = {
a:"abc",
b:"def"
}
}
In this example, the text in block2 is set to the initial values of test.a
and test.b
. The input values and <p>
values inside of the loop are also set to the initial value.
When I modify the values within the inputs, the <p>
values inside of the ng-repeat block update correctly, but the <p>
tags in block2 fail to update.
Why is this the behavior? Does ng-repeat create its own isolated scope? If so how can I get the controller level scope to update? Also, could somebody explain the thinking behind this behavior and any advantages it provides?
JSFiddle Showing the problem
Share Improve this question edited Dec 14, 2013 at 23:30 Ben McCormick asked Dec 14, 2013 at 23:24 Ben McCormickBen McCormick 25.7k12 gold badges55 silver badges71 bronze badges2 Answers
Reset to default 23ng-repeat
creates a child scope for each repeated item. As a result you are trying to pass a primitive to child scope which won't create a reference to parent. When you pass objects however, you pass the original object reference.
From the mouth of one of the fathers of Angular:
Always have a dot in ng-model
This is a great video regarding Angular Best Practices given by Angular creator (2012/12/11). Go to minute 31 for well explained detail of this exact situation
Modify data to array of objects:
$scope.test = [{ val:"abc",key:'a'}, {val:"def",key:'b'} ]
Then in repeater:
<form ng-repeat="item in test">
<label>{{item.key}}</label>
<input ng-model="item.val" />
<p>{{item.val}}</p>
</form>
DEMO
try this:
angular.module('App', []);
function Ctrl($scope) {
$scope.test = [
{label:"a", value:"abc"},
{label:"b", value:"def"}
]
}
and
<div ng-app="App">
<div ng-controller="Ctrl">
<div class="block1">
<form ng-repeat="o in test">
<label>{{o.label}}</label>
<input ng-model="o.value" />
<p>{{o.value}}</p>
</form>
</div>
<div class="block2">
<p>
{{test[0].value}}
</p>
<p>
{{test[1].value}}
</p>
</div>
</div>
</div>
Angularjs uses the fact that objects are passed by reference. So, if you pass a object to a function and change the object inside the function, the object outside also changes. Look at this updated JSFiddle