Stefan
Stefan

Reputation: 4160

Angularjs ng-repeat input blur after one keystroke

If I try to do a ng-repeat to databind some fields to an array for example using the $index value then the input blurs automagically after 1 keystroke. Check the example to see what i mean.

(tested with angular stable 1.2.4 and latest: 1.2.5, and 1.1.1 from jsfiddle)

(fiddle: http://jsfiddle.net/Dj4n4/)

or the html bellow, same thing

<!doctype html>
<html ng-app>
  <head>
    <script src="js/angular.js"></script>
    <script type="text/javascript">
      function testController ($scope) {
        $scope.data = {
          a: 1,
          b: '2222',
          c: {
            d: 3,
            e: [1, 2, 3],
          }
        };
      }
    </script>
  </head>

  <body ng-controller="testController">
    Works: <label><input type="text" ng-model="data.c.e[1]" /></label>
    <br />
    Blurs after one keystroke:
    <label ng-repeat="no in data.c.e">
      <input type="text" ng-model="data.c.e[$index]" />
    </label>
    <pre>{{data | json}}</pre>
  </body>
</html>

Upvotes: 4

Views: 796

Answers (2)

Stefan
Stefan

Reputation: 4160

I got a great answer from Michael Hard on the AngularJS Google Groups:

https://groups.google.com/forum/#!topic/angular/q1U-9Dj7leU

The solution is to use Angular >= 1.2.4 (the currently stable one works) and use track by in the ng-repeat, aka:

<label ng-repeat="no in data.c.e track by $index">

And the whole code:

<!doctype html>
<html ng-app>
  <head>
    <script src="js/angular.js"></script>
    <script type="text/javascript">
      function testController ($scope) {
        $scope.data = {
          a: 1,
          b: '2222',
          c: {
            d: 3,
            e: [1, 2, 3],
          }
        };
      }
    </script>
  </head>

  <body ng-controller="testController">
    Works: <label><input type="text" ng-model="data.c.e[1]" /></label>
    <br />
    Blurs after one keystroke:
    <label ng-repeat="no in data.c.e track by $index">
      <input type="text" ng-model="data.c.e[$index]" />
    </label>
    <pre>{{data | json}}</pre>
  </body>
</html>

Upvotes: 4

Matt Zeunert
Matt Zeunert

Reputation: 16571

It's because ng-repeat redraws every time the value changes. It works if you bind to integers in an object instead of an array:

f: [{no:1},{no:2},{no:3}]
// ...
<input type="text" ng-model="data.c.f[$index].no" />

Fiddle

You could watch a proxy object like that and use it to update the array.

$scope.$watch("data.c.f", function(){
    $scope.data.c.e = [];
    $scope.data.c.f.forEach(function(obj){
        $scope.data.c.e.push(obj.no);
    })
}, true)

Upvotes: 1

Related Questions