7

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

2 Answers 2

23

ng-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

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the clear explanation of the behavior. My use case requires that I reference the properties of "test" by name in the outer scope, so an array doesn't work for me, but sub objects seem to work fine.
My Object keys are UNIX times, so this is very difficult for me
@neaumusic comment not clear, post a question if you need help
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.