Divya MV
Divya MV

Reputation: 2053

AngularJS: How to Know when angular has done refreshing all the bindings in the view

In mainPage.html we are dispaying a table from an object names.

 <table>
  <tr ng-repeat="x in names">
  <td>{{ x.Name }}</td>
  <td>{{ x.Country }}</td>
  </tr>
 </table>

and when the user clicks on next button a rest request for next set of names is being dispatched. I am displaying a loading image immediately after clicking on the next Button. I want to hide the loading image only after the new set of data is reflected in the table. How can I know if angular has finished updating the DOM with the new set of data?

Upvotes: 1

Views: 1607

Answers (4)

tpie
tpie

Reputation: 6221

I would agree with Dylan Watt, though I think I would want to use $http's built promise, with success and error for a little cleaner handling if there is a problem.

Set a var that enabled the loading state, make your ajax call, change the loading state back on success of that ajax call (or do something else in case of an error).

$scope.getFunction = function () {
  $scope.loading = true;
  $http.get('/someUrl').
    success(function(data, status, headers, config) {
      $scope.names = data;
      $scope.loading = false;
    }).
    error(function(data, status, headers, config) {
      // gracefully handle the error here
    });
}

If the above doesn't solve your issue, and the following is your concern:

no if you have lets say 1000s of rows in your response, then the time when the $http finishes, and the time by when angular's digest cycles get over.. there would be a significant lag... what the question ask is - how to identify when the last digest cycle has finished – entre

One potential solution (though I am not convinced this is a great way) would be something along the lines of this post: How to watch the DOM for changes AngularJS

and set a timeout to wait until no DOM changes occur for a set period of time. I have not seen anywhere that you can identify when the last $digest cycle occurs specifically. In the case of large amounts of data being blasted through ng-repeat, you should see a burst of DOM population, and then it should go quiet.

A better solution seems to be to use an 'element-ready' directive which triggers the $rootScope.loading = false once it has loaded, as described in the following post: Sending event when angular.js finished loading

Upvotes: 0

floribon
floribon

Reputation: 19183

As soon as the $http call ends, Angular will trigger a digest phase (via $apply). Any code executed after that digest phase will be executed after the HTML has been updated.

One way to make sure your code is executed after the digest phase is to use setTimeout or $timeout. For instance:

$http.get(url).success(function() {
  // Update the scope
  $scope.data = data;
  // Wait for the DOM to be up do date (end of digest cycle)
  $timeout(function() {
    // Here you can safely remove your loading things
  });
});

However if the image itself is added/removed by Angular (using ng-show or ng-if for instance), then you don't event need that $timeout: the image will be hidden from the view at the same time as the view is being updated. This will happen in the same digest cycle.

Upvotes: 3

Dylan Watt
Dylan Watt

Reputation: 3387

I'm making the assumption that you are requesting the next set of names via $http. If not, the same pattern applies with async actions in general, as long as you use promises.

With the following, everything happens in the Angular runtime. The data point for the show/hide is updated at the same time as names and thus they will update in the same digest cycle, and thus render at the same time on the DOM.

In general, keeping everything in angular and keying everything off the $scope in your view makes it easy to keep things in sync.

.controller('tableController', function($http, $scope){
    $scope.loading = false;
    $scope.getSomeNames = function(){
       $scope.loading = true; 
       $http.get('names').then(function(reponse){
            $scope.loading = false;
            $scope.names = response.data
       })
    })

})

HTML:

<table ng-controller="tableController">
  <tr ng-repeat="x in names" ng-hide="loading">
  <td>{{ x.Name }}</td>
  <td>{{ x.Country }}</td>
  </tr>
  <tr ng-show="loading"><td>Loading</td></tr
</table>

Upvotes: 1

stackg91
stackg91

Reputation: 594

Im not really sure if that helps you but some1 created a onNg-repeatfinished Handler maybe u can apply this for ur table but im not sure ngrepeatfinishedHandler

Upvotes: 2

Related Questions