简体   繁体   中英

Template flicker when url changes in Angular

I'm developing a small application with angular and I'm having a hard time solving the template flicker (shows one template then immediately shows another one) problem I'm facing.

I have an <ng-view> tag defined in my base template and a few partial files.

This is my routeProvider setting:

app.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/', {
        templateUrl: '/static/partials/login.html',
        controller: 'LoginController',
        requireLogin: false
      }).
      when('/login', {
        templateUrl: '/static/partials/login.html',
        controller: 'LoginController',
        requireLogin: false
      }).
      when('/register', {
        templateUrl: '/static/partials/register.html',
        controller: 'RegisterController',
        requireLogin: false
      }).
      when('/profile', {
        templateUrl: '/static/partials/profile.html',
        controller: 'ProfileController',
        requireLogin: true
      }).
      otherwise({
        redirectTo: '/'
      });
}]);

As you can see, I'm defining a requireLogin property to check if the corresponding route requires the user to be logged into the webapp.

The following is an interceptor I defined that checks if the requireLogin property is set and if it is, it asks the server if the user is authenticated. If the user is not authenticated it redirects him to the login page.

 app.run(function($rootScope, $location, $http) {
        $rootScope.$on('$routeChangeStart' , function(event, current) {
            if(current.requireLogin) {
              $http.get('/authenticated').success(function(response){
                if(!response.authenticated) {
                  $location.path('/');
                }
              });
            }
         });
    });

The flicker happens when the user is not authenticated.

$routeProvider supports a 'resolve' property, which addresses the flicker by delaying the route change until all promises from the resolve object have been resolved. The resolve properties are injectable into your controller function. Here is an example of how it works:

  when('/profile', {
    templateUrl: '/static/partials/profile.html',
    controller: function($scope, profile, loginInfo) {
         $scope.data = profile.data;
         $scope.loginInfo = loginInfo;
    },
    requireLogin: true,
    resolve:  {
         profile: function($http) {
             // return a promise
             return $http({ method: 'GET', url:'/getProfile' });
        },
        loginInfo: function() {
             // return an object literal
             return  { details: { ... } }
        }, 
        etc
    }
  }).

Look into ngClock. This could be a solution. https://docs.angularjs.org/api/ng/directive/ngCloak .It states that

"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".

As answered before: you can use ng-cloak.

but i think it would not solve your problem, because the request happens afterwards.

maybe you can use a modal to ask for the credentials of the user. i do something similar and it works perfekt. (the modal shows with fade in if the user isn't authorized)

in your $routeChangeStart event you can check if authorization is needed. if not, send a loginRequired broadcast.

    $rootScope.$on('$stateChangeStart', function (event, nextState) {
            if (nextState.requireLogin) {
                event.preventDefault();
                $rootScope.$broadcast('auth-change', 'loginRequired', nextState.name);
            }
        });

a logincontroller handles the loginRequired event and displays the modal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM