Wait until scope variable is loaded before using it in the view in angular.js

All we need is an easy explanation of the problem, so here it is.

I’ve seen this and this but it seems like there might be a simpler way.

In my view I have several menu options that are controlled through permissioning – i.e., not everyone can see a “Dashboard” view. So in my menu option in my view I have something like the following:

<li ng-show="validatePermission('Dashboard')">Dashboard</li>

In my controller I have a validatePermission method defined where it is looking at the permissions of the current user. For example:

  $scope.validatePermission = function(objectName) {
    if $scope.allPermissions......

Also in my controller I’m loading those permissions via an $http call:

  $http.get('permissions/' + userid + '.json').success(function(data) {  
    $scope.allPermissions = data;....

The issue is that $scope.allPermissions doesn’t get loaded before the view makes the call to validatePermission. How can I wait for allPermissions to be loaded before the view renders?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

You ask:

How can I wait for allPermissions to be loaded before the view renders?

To prevent the entire view from rendering, you must use resolve. You don’t have to use the promise library though, since $http returns a promise:

var app = angular.module('app');

app.config(function ($routeProvider) { 
  $routeProvider
    .when('/', {
        templateUrl : 'template.html',
        controller : 'MyCtrl',
        resolve : MyCtrl.resolve
  });
});

function MyCtrl ($scope, myHttpResponse) {
   // controller logic
}

MyCtrl.resolve = {
  myHttpResponse : function($http) {
    return $http({
        method: 'GET',
        url: 'http://example.com'
    })
    .success(function(data, status) {
        // Probably no need to do anything here.
    })
    .error(function(data, status){
        // Maybe add an error message to a service here.
        // In this case your $http promise was rejected automatically and the view won't render.
    });
  }
}

But if you simply want to hide the dashboard <li>, then do as Joe Gauterin suggested. Here’s a very simple example plunkr if you need it.

Method 2

Have the validatedPermission function return false when allPermissions hasn’t been loaded. That way the element with your ng-show won’t be displayed until allPermissions has been loaded.

Alternatively, put an ng-show="allPermissions" on the enclosing <ul> or <ol>.

Method 3

You can also specify on your routecontroller a resolve object that will wait for that object to resolve prior to rendering that route.

From the angular docs: https://docs.angularjs.org/api/ngRoute/provider/$routeProvider

resolve – {Object.=} – An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $routeChangeSuccess event is fired. The map object is:

key – {string}: a name of a dependency to be injected into the controller.
factory – {string|function}: If string then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before its value is injected into the controller.

A google group reference as well: https://groups.google.com/forum/#!topic/angular/QtO8QoxSjYw

Method 4

I encountered an similar situation, you might also want to take a quick look at

http://docs.angularjs.org/api/ng/directive/ngCloak

if you’re still seeing a “flicker” effect.

As per the angularjs documentation:

The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

Method 5

Wrapping the code in ng-if fixed the issue for me:

<div ng-if="dependentObject">
  <!-- code for dependentObject goes here -->
</div>

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply