-->

How to do preloader for `ng-view` in Angular JS?

2019-02-15 23:20发布

问题:

I use <div ng-view></div> on web page. When I click link in block <div> is loaded HTML template was set in routeProvider. Also together is done request AJAX that returns data that was loaded template.

Now problem is that after click I get HTML template with empty form, still is working AJAX request. After some seconds form HTML is fiiled data from AJAX.

How I can do preloader to page for directory ng-view?

回答1:

It seems that there are some similar questions here:

  • Angularjs loading screen on ajax request
  • Angular JS loading screen and page animation.

Also, there a bunch of modules to work with loading animation at http://ngmodules.org. For example, these:

  • https://github.com/cgross/angular-busy
  • https://github.com/chieffancypants/angular-loading-bar (I use this one in my apps)
  • https://github.com/McNull/angular-block-ui and other.

UPD: I've written a simple solution based on how the angular-loading-bar works. I didn't test it with ng-view, but it seams to work with ui-view. It is not a final solution and have to be polished.

angular.module('ui')

.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('LoadingListener');
}])

.factory('LoadingListener', [ '$q', '$rootScope', function($q, $rootScope) {
    var reqsActive = 0;

    function onResponse() {
        reqsActive--;
        if (reqsActive === 0) {
            $rootScope.$broadcast('loading:completed');
        }
    }

    return {
        'request': function(config) {
            if (reqsActive === 0) {
                $rootScope.$broadcast('loading:started');
            }
            reqsActive++;
            return config;
        },
        'response': function(response) {
            if (!response || !response.config) {
                return response;
            }
            onResponse();
            return response;
        },
        'responseError': function(rejection) {
            if (!rejection || !rejection.config) {
                return $q.reject(rejection);
            }
            onResponse();
            return $q.reject(rejection);
        },
        isLoadingActive : function() {
            return reqsActive === 0;
        }
    };
}])

.directive('loadingListener', [ '$rootScope', 'LoadingListener', function($rootScope, LoadingListener) {

    var tpl = '<div class="loading-indicator" style="position: absolute; height: 100%; width: 100%; background-color: #fff; z-index: 1000">Loading...</div>';

    return {
        restrict: 'CA',
        link: function linkFn(scope, elem, attr) {
            var indicator = angular.element(tpl);
            elem.prepend(indicator);

            elem.css('position', 'relative');
            if (!LoadingListener.isLoadingActive()) {
                indicator.css('display', 'none');
            }

            $rootScope.$on('loading:started', function () {
                indicator.css('display', 'block');
            });
            $rootScope.$on('loading:completed', function () {
                indicator.css('display', 'none');
            });
        }
    };
}]);

It can be used like this:

<section class="content ui-view" loading-listener></section>


回答2:

You can try something like this(simplest solution):

  1. Set your loader animation/picture:<div class="loader" ng-show="isLoading"></div>

  2. On div element add click event:

  3. Then AJAX request success set isLoading=true


回答3:

Download javascript and css files from PACE Loader. Playing around with pace loader using ng-views . Hope this helps someone trying to use PACE.JS with Angular. In this example I am using ng-router to navigate between views.

app.js

var animateApp = angular.module('route-change-loader', ['ngRoute']);

var slowResolve = function(slowDataService){
    return slowDataService.getContacts();
  };
  slowResolve.$inject = ['slowDataService'];

// ROUTING ===============================================
// set our routing for this application
  // each route will pull in a different controller
  animateApp.config(function($routeProvider) {

    $routeProvider

    // home page
    .when('/route1', {
      templateUrl: 'route1.html',
      controller: 'slowCtrl',
      controllerAs:'ctrl',
      resolve: {
        contacts:slowResolve
      }
    })
    .otherwise({
      templateUrl:'default.html'
    });
  });


var SlowCtrl = function(contacts) {
  this.contacts = contacts;
};
  SlowCtrl.$inject = ['contacts'];

  angular.extend(SlowCtrl.prototype, {
    message:'Look Mom, No Lag!',
    contacts: []
  });

animateApp.controller('slowCtrl', SlowCtrl);


  var SlowDataService = function($timeout){
      this.$timeout = $timeout;
    };
    SlowDataService.$inject = ['$timeout'];

    angular.extend(SlowDataService.prototype, {
      contacts:[{
        name:'Todd Moto',
        blog:'http://toddmotto.com/',
        twitter:'@toddmotto'
      },{
        name:'Jeremy Likness',
        blog:'http://csharperimage.jeremylikness.com/',
        twitter:'@jeremylikness'
      },{
        name:'John Papa',
        blog:'http://www.johnpapa.net/',
        twitter:'@John_Papa'
      },{
        name:'Josh Carroll',
        blog:'http://www.technofattie.com/',
        twitter:'@jwcarroll'
      }],
      getContacts:function(){
        var _this = this;
        return this.$timeout(function(){
          return angular.copy(_this.contacts);
        }, 1000);
      }
    });

animateApp.service('slowDataService', SlowDataService);

index.html

<!DOCTYPE html>
<html lang="en-us">
<head>
  <meta charset="utf-8">
  <title>Test Example</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
  <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="pace.css">
  <script src="http://code.angularjs.org/1.2.13/angular.js"></script>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular-route.js"></script>
  <script src="app.js"></script>
  <script src="pace.js"></script>

</head>
<body ng-app="route-change-loader">
  <div class="container">
    <div class="masthead">
      <ul class="nav nav-tabs">
        <li>
          <a href="#/default">Default</a>
        </li>
        <li>
          <a href="#/route1">Slow Loading Controller</a>
        </li>
      </ul>
    </div>
    <!-- Jumbotron -->
    <div class="row">
      <route-loading-indicator></route-loading-indicator>
      <div ng-if="!isRouteLoading" class="col-lg-12" ng-view=""></div>
    </div>
    <!-- Site footer -->
    <div class="footer">
      <p>by <b>Ritesh Karwa</b> </a>
      </p>
    </div>
  </div>
</body>

</html>

default.html

<h1>Click on the tabs to change routes</h1>

route1.html

<h1>{{ctrl.message}}</h1>
<table class="table table-striped">
  <thead>
    <tr>
      <th>Name</th>
      <th>Blog</th>
      <th>Twitter</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat='contact in ctrl.contacts'>
      <td>{{contact.name}}</td>
      <td>{{contact.blog}}</td>
      <td>{{contact.twitter}}</td>
    </tr>
  </tbody>
</table>