Resolving the $rootScope:infdig infinite looping issue

I understand the concept of the infinite digest loop and how it occurs, but I am encountering an issue. You can see my code and problem demonstrated in this fiddle:

http://jsfiddle.net/eS5e5/1/

If you check the console in the jsfiddle, you'll notice the infinite digest loop.

The crux of the issue is that I need to make decisions based on data that may not have loaded yet, so I have to wait for the promise to resolve using then(). I have a promise named user, on which I call then() in two different places in the code.

  1. Right after I define it, in order to set a scope variable based on it.
  2. In another scope method called $scope.isAdmin()

Regarding the second point, one might wonder why I don't simply use $scope.user directly within the $scope.isAdmin() method. The reason is that there's a possibility for $scope.isAdmin() to be invoked before the async request for the user completes, necessitating a 'block' before returning from $scope.isAdmin().

So, my question is: what aspect of $scope.isAdmin() makes Angular perceive that a 'watched' variable has changed and triggers the digest cycle?

After all, $scope.isAdmin() itself does not alter anything.

Here is the simplified code snippet:

HTML:

<body ng-controller='myController'>  
  <div ng-if='isAdmin()'>Hi! <strong>{{ user.username }}</strong> is an Admin!!!</div>
  <div ng-if='!isAdmin()'>Hi! <strong>{{ user.username }}</strong> is NOT an Admin!!!</div>
</body>

And the JavaScript:

angular.module('myApp', [])
  .factory('myService', function($q, $timeout) {
    return {        
      getUser: function() {
        var deferred = $q.defer();

        $timeout(function() {
          deferred.resolve({ username: 'me', isAdmin: true });
        }, 2000);

        return deferred.promise;
      }
    };
  })
  .controller('myController', function($scope, $q, myService) {      
    var getUserDeferred = $q.defer();
    var user = getUserDeferred.promise;
    user.then(function(user) {
      $scope.user = user;
      return user;
    });

    $scope.getUser = function() {
      return myService.getUser().then(function(user) {
        getUserDeferred.resolve(user);
      });
    };

    $scope.isAdmin = function() {
      return user.then(function(user) {
        return user.isAdmin;
      });
    };

    $scope.getUser();
  });

Answer №1

After finding a solution to my own issue, I wanted to share it here in case it can help others facing the same problem.

The key to resolving the issue was understanding and leveraging two important concepts: angular promises and angular watches. By effectively utilizing these two concepts together, I was able to simplify the fix.

It's essential to remember that everything placed on $scope is constantly 'watched', including functions. Whenever a watched item changes, $scope.$apply() is triggered to apply those changes. If a scope function (e.g., $scope.isAdmin()) changes its return value between 'apply' cycles, it will lead to consecutive 'apply' executions until the return value stabilizes.

In my code, I had been returning user.then(...) which generated a new promise each time (resulting in an ongoing apply cycle due to the changing return value).

To address this issue within my isAdmin() function, I needed to delay the return value until the user data had actually loaded (as any other return value would be meaningless). Therefore, I modified the code to confirm if the user async call had resolved by checking $scope.user, and then returned a valid isAdmin value when appropriate. If $scope.user remained undefined, I simply returned the existing promise.

The updated $scope.isAdmin() function now looks like:

$scope.isAdmin = function() {
  if ($scope.user) {
    return $scope.user.isAdmin;
  }

  return user;
};

This adjustment achieved the same outcome as the original code without triggering an infinite apply cycle. Notably, if $scope.user is unresolved, we still return a promise by using the user variable. It's important to note that the user variable remains the same promise, rather than creating a new one through then(), which helps stabilize the apply cycle.

For reference, you can view the updated jsfiddle here:

http://jsfiddle.net/eS5e5/2/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring the application of the Angular Controller and how it interfaces with the controllerAs

When trying to learn Angular, I often come across articles that leave me puzzled. One particular aspect that has me stuck is the significance of keywords Controller and controllerAs in directives. I found the code snippet on this website: app.controller ...

How can generators and Q be used in the simplest fs.readFile example?

I have relied on node's async as my primary flow control mechanism for quite some time now. It has always worked well for me, without the need to delve into discussions or further reading about it. Now, I am intrigued by the possibility of using gene ...

Is there a way to determine the exported functions from a node/npm package?

After posting my previous question on accessing functions through imported packages and researching the import statement according to Mozilla's documentation, I have realized that I need to follow these steps to utilize the features in a module: imp ...

Obtaining a specific item from a group using AngularJS. Utilizing a declarative method

Consider a scenario where you need to apply a CSS rule to a specific element within a collection that needs to be selected. <div ng-repeat="fragments" ng-click="makeSelected()"></div> $scope.fragments = [ {id: 6379, someProperty: "someValu ...

Struggling to get getInitialProps working in dynamic routes with Next.js?

I am encountering an issue. The return value from the getInitialProps function is not being passed to the parent component. However, when I console.log the values inside the getInitialProps function, they appear to be correct. Here is the code snippet: i ...

A pair of demands within an express service

Currently, I'm facing an issue in a project where I am attempting to create a service using Express that makes two external API calls. However, I am encountering an error in Express that is difficult to comprehend. It seems like my approach might be i ...

Vue.js - Exploring methods to append an array to the existing data

I am looking to structure my data in the following way: Category 1 Company 1 Company 2 Company 3 Category 2 Company 1 Company 2 Company 3 Below is my code snippet: getlist() { var list = this.lists; var category this.$htt ...

Iterate through and remove elements within an array containing objects

Within my Vue.js application, I am working with an array of objects that I need to iterate through and display in the web browser. The array consists of four objects, but I only wish to show three based on a user's preference setting stored in a varia ...

Creating a conditional statement in jQuery that will append text to a specific DIV element after a form has been successfully

I currently have a form set up that is functioning properly, but I am looking to make some changes. Instead of redirecting the user to a new page with a success message upon submitting the form, I want the success message to be displayed in a div next to t ...

How can I implement pagination using jQuery?

I'm looking to incorporate jQuery pagination in my CodeIgniter project. After doing some research on the CodeIgniter forum and CodeIgniter AJAX Pagination Example/Guideline, I came across suggestions to check out a solution on TOHIN's blog. Howe ...

How can we guide the user to a different page when a particular result is retrieved by AJAX?

Whenever my PHP function makes a database call, I receive multiple results. The ajax then displays these results in a div element. My question is: How can I redirect the user to the next page once I obtain a specific result from the PHP function? Current ...

What steps can be taken to avoid caching PHP variables?

My code in functions.php on WordPress generates an affiliate link based on the visitor's location. It works perfectly, but there's a problem with page caching (W3 Total Cache). The variables get cached, so if a visitor from the UK opens the page ...

Ways to ensure that the dropdown content remains visible even after the mouse has exited the trigger element

There are three buttons arranged in a row, and when one is hovered over, dropdown content appears underneath all three buttons. However, the content disappears when the mouse moves down to it. Unfortunately, images cannot be posted inside yet** https://i.s ...

Using Set in combination with useRef: A Beginner's Guide

Trying to implement Set with useRef. Below is my attempt. export default function App() { const data = useRef<Set<string>>(new Set()); const add = () => { data.current = new Set([...Array.from(data.current), ...

Utilizing AngularJS to dynamically inject HTML content into $scope

In my possession are the following files: index.html //includes instructions for passing arguments to the btnClick function in app.js <div ng-bind-html="currentDisplay"></div> app.js app.factory('oneFac', function ($http){ var htm ...

Craft a Flawlessly Repeating Sound Experience - Online

I'm facing a challenge in creating a flawless loop of an audio file. However, all the methods I've tried so far have resulted in a noticeable gap between the end and the start. Here are the approaches I experimented with: The first approach inv ...

When I attempt to incorporate multiple sliders on a single page, I encounter difficulties in determining the accurate stopping position if the number of slides varies

I am having trouble setting the correct stop position for sliders with different numbers of slides on a page. When I have the same number of slides in each slider, everything works fine. However, I need to have a different number of slides in each slider ...

Is it possible to utilize one controller within another controller in angularjs?

I am interested in using the Angular JS scrollbar to display content. Here are the controllers I plan to utilize: module.controller('itemsCtrl', function($scope){ $scope.items = [ {src:'../static/images/image-3.png&apos ...

Guide on implementing a personalized 'editComponent' feature in material-table

I'm currently integrating 'material-table' into my project. In the 'icon' column, I have icon names that I want to be able to change by selecting them from an external dialog. However, I am encountering issues when trying to update ...

Image does not appear on server side when using FormData for AJAX image upload

I am currently working on an image upload system where the image is uploaded as soon as it is selected in the input[type='file'] element. Despite my efforts, I am facing challenges in transferring the image to the server side. Scenario HTML: & ...