简体   繁体   中英

AngularJS ng-repeat one time binding a nested method call

I am experimenting with AngularJS 1.3 (I just migrated my app from 1.2). I am playing with the new one-time binding. I have come across this case where it is not working, can someone please explain why? I am dynamically generating an id field by calling a method within the view. As a result, the one-time binding does not seem to be working. See http://plnkr.co/edit/GyfKKb?p=preview .

Specifically, I'm expecting the one-time to not re-render the ng-repeat when a new element is added to the array. But pushing a new element into the array (via button click) also makes the new element appear in the output of the ng-repeat .

index.html

<body ng-controller="MainCtrl">
  <!-- TODO: I would expect addItemC() to do nothing with one time binding -->
  <button ng-click="addItemC()">add</button>

  <div ng-repeat="itemC in ::itemsC">

    <!-- dynamically generate id that is cause breakage -->
    {{::itemC.id() | limitTo:3}}

  </div>      
</div>

app.js

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {

  // generate random string id dynamically (code taken from stackoverlow answer)
  var itemObj = {
    id: function makeid() {
      var text = "";
      var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

      for( var i=0; i < 100; i++ )
          text += possible.charAt(Math.floor(Math.random() * possible.length));

      return text;
    }
  };

  // one time binding does not work
  $scope.itemsC = [
    angular.copy(itemObj),
    angular.copy(itemObj),
    angular.copy(itemObj)
  ];
  $scope.addItemC = function() {
    $scope.itemsC.push(angular.copy(itemObj));
  }
});

I think it is because of exceeding number of $digest cycles inside the ng-repeat angular is throwing error. Mostly it is because of the for loop running for 100 iterations for every item.

If you change you logic to generate the id inside the controller and then give the item to ng-repeat to render then it works fine. Take a look at my plunkr

Demo http://plnkr.co/edit/4nFtOy1uGtDyUEWXCVbT?p=preview

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';

  // generate random string id dynamically (code taken from stackoverlow answer)
  function makeid() {
      var text = "";
      var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

      for( var i=0; i < 100; i++ )
          text += possible.charAt(Math.floor(Math.random() * possible.length));

      return text;
    }

  function getItem () {
    return {
      id: makeid()
    };
  }


  var itemObj = {
    id: makeid()
  };


  // one time binding does not work
  $scope.itemsC = [
    getItem(),
    getItem(),
    getItem(),
  ];
  $scope.addItemC = function() {
    $scope.itemsC.push(getItem());
  }

  $scope.removeItem = function(item) {
    var index = $scope.itemsC.indexOf(item);
    $scope.itemsC.splice(index, 1);
  }
});

Inside the markup change itemC.id() to itemC.id since id is now property.

I think because you are one time binding the function and calling the function every time. Calling a function inside double curly braces will give whatever the function returns. The function remains the same by keep returning random strings.

So, one time binding actually works here by keep calling the same function. Note that the function does not change. I added new property which is not a function to the object to show you the one time binding actually works.

<div style="font-weight:bold;">itemsC:</div>
<div ng-repeat="itemC in ::itemsC">
  <div ng-click="removeItem(itemC)">
    <!-- dynamically generate id -->
    {{::itemC.name | limitTo:3 }}
  </div>
</div>
<div style="margin-top:10px;">{{itemsC}}</div>

http://plnkr.co/edit/T8KRafey7VJFbcAs4NLZ?p=preview

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM