function inside ngRepeat executed too often

I have three tabs that has different html inside ng-include. These tabs are shown using ng-repeat. Only one HTML template contains function call, but it's executed 3 times (once per ng-repeat iteration). What is wrong here and how to fix it?

var app = angular.module('myApp', [])
app.controller('myCtrl', [
  '$scope',
  function($scope){
    $scope.randomFnc = function (i) {
      console.log(i);
      return "Placeholder text";
    }
    $scope.tabs = [
      "a",
      "b",
      "c"
    ];
  }
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
     <div ng-repeat="tab in tabs">
        <div ng-if="$index == 1">
          {{$index}}<input type="text" value="" placeholder="{{randomFnc($index)}}"/>
        </div>
        <div ng-if="$index != 1">{{$index}}</div>
     </div>
</div>
</div>

Answers:

Answer

You can use ng-init though it is not highly recommended to achieve this. The reason why your function call is being executed thrice is because angular doesn't know if any $scope value has changed during each digest cycle. So the function will get executed for each digest cycles. In your case, it will get executed when the ng-if conditions become true as well as during the two digest cycles accounting a total of three. This is the reason why it gets executed 3 times with the value 1 regardless of the number of items in the array.

var app = angular.module('myApp', [])
app.controller('myCtrl', [
    '$scope',
    function($scope) {
        $scope.x = {};
        $scope.randomFnc = function() {
            console.log("once");
            $scope.placeholderText = "Placeholder text";
        }
        $scope.tabs = [
            "a",
            "b",
            "c"
        ];
    }
])
app.directive('trackDigests', function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;

        function countDigests() {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
    <div ng-controller="myCtrl">
        <div ng-repeat="tab in tabs">
            <div ng-if="$index == 1" ng-init="randomFnc()">
                {{$index}}<input type="text" value="" placeholder="{{placeholderText}}" />
            </div>
            <div ng-if="$index != 1">{{$index}}</div>
        </div>
    </div>
    <track-digests></track-digests>
</div>

Answer

Call a method for 3 times because placeholder attribute or other attributes like this as class or ... can't define the ng- in angularjs, for solution we can use ng-init to handle it.

when you run the first you have repeat and then binding elements and then your angular attributes runs.

for best solution i refer to use model as object to binding placeholder on it, it's easily.

var app = angular.module('myApp', [])
app.controller('myCtrl', [
  '$scope',
  function($scope){
    $scope.placeholder = "";
    $scope.randomFnc = function (tab) {
       $scope.placeholder = "Placeholder text";
    }
    
    $scope.tabs = [
      "a",
      "b",
      "c"
    ];
    
    //----2
    
    $scope.randomFnc2 = function (tab) {
      tab.placeholder = "Placeholder text";
    }
    
    $scope.tabs2 = [
      {name: "a"},
      {name: "b"},
      {name: "c"},
    ];
  }
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<h1>better if you use model</h1>
     <div ng-repeat="tab in tabs2">
        <div ng-if="$index == 1" ng-init="randomFnc2(tab)">
          {{$index}}
          <input type="text" value="" placeholder="{{tab.placeholder}}"/>
        </div>
        <div ng-if="$index != 1">{{$index}}</div>
     </div>

<h1>also you can</h1>

     <div ng-repeat="tab in tabs">
        <div ng-if="$index == 1" ng-init="randomFnc(tab)">
          {{$index}}
          <input type="text" value="" placeholder="{{placeholder}}"/>
        </div>
        <div ng-if="$index != 1">{{$index}}</div>
     </div>
     
</div>
</div>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.