Angularjs: Why does it execute function in ng-if when I click on table row?

840 Views Asked by At

I have code on https://jsfiddle.net/8t45enfg/2/
The source code is quite simple, suppose the array list have only one element
HTML code:

<div ng-controller="myController">
   <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Job</th>
      </tr>
      <tr ng-repeat="a in list" ng-click='doClick()'>
        <td ng-if='doCheck()'>{{ a.name }}</td>
        <td>{{ a.age }}</td>
        <td>{{ a.job }}</td>
      </tr>
   </table>
</div>

Js code

module.controller("myController", function($scope) {
  $scope.list = [ { name: 'test', age: 100, job: 'IT'} ]
  $scope.doClick = function() {
    console.log('doClick');
  }
  $scope.doCheck = function() {
    console.log('doCheck');
    return true;
  }
});

  1. When I run my code, doCheck() is executed twice, why? It should be executed once
  2. The main question is when I click on data row, both doCheck and doClick are called, I thought it would call just doClick, not doCheck, because I had no action on doCheck. This made me difficult to understand
3

There are 3 best solutions below

0
On

I'm not a complete expert on the topic but here is my understanding of your problem.

Whenever a change is made on your page, the page is set to "dirty" and when the next cycle hits the ng-if, it will be re-evaluated.

So to answer your first question, the ng-if is evaluated when it is loaded (calling doCheck()), then the rest of the page is loaded, causing the page to be set to "dirty", so the ng-if is re-evaluated, causing doCheck() to be called again.

This causes "doCheck" to appear twice.

This is the same for your second question. Whenever you click, the doCheck() is re-evaluated, causing both doClick() and doCheck() to be called. If you want to avoid doCheck() being called each time, use a variable in your ng-if, then create a function to change that variable.

I hope that helps, I'm sure some angular wizard will be able to give you a better answer!

0
On

It is because of Angular’s Digest Cycle

Here are some important quote from Dave Ceddia Blog — Controller Function Is Executed Multiple Times to help you understand the reason:

Angular’s Digest Cycle

What you are seeing is the digest cycle at work. The digest cycle is how Angular’s auto-update magic works – it’s the reason that typing into an input box automatically updates anything that refers to its value.

When the digest cycle runs, it effectively redraws everything that might have changed on the page.

Angular uses some tricks to find “everything that might have changed”, and the main technique is watchers. These watchers are created automatically when you use directives like ng-if and ng-class, and when you use bindings like {{ yourBindingHere }}.

Each one of those things registers a watcher. When Angular’s digest cycle runs, every watcher is asked to update its state. In the case of ng-class, it will re-run the function bound to it, to see if anything needs to change. This is why your controller function runs multiple times, and it’ll run again each time something changes on the page.

0
On

For the Q1.
doCheck() is the function which you created, which mean it will check each time when the html run. If you want to do check condition for the tag then you must use the variable rather than the function.

For the Q2. When you click the row doClick will fire and then the doCheck function also will run because you have used that function in the ng-if condition, So that will re-evaluate again

I hope this answer will help you to understand. I have modified your code with small changes.

<div ng-controller="myController">
 <table>
  <tr>
    <th>Name</th>
    <th>Age</th>
    <th>Job</th>
  </tr>

  <tr ng-repeat="a in list" ng-click='doClick()'>
    <td ng-if='doCheckCondition'>{{ a.name }}</td>
    <td>{{ a.age }}</td>
    <td>{{ a.job }}</td>
  </tr>
 </table>
</div>

JS Script

module.controller("myController", function($scope) {
  $scope.list = [ { name: 'test', age: 100, job: 'IT'} ]
  $scope.doClick = function() {
     console.log('doClick');

     //Do something and set it true the $scope.doCheckCondition
  }
  $scope.doCheckCondition = false