AngularJS: How to show preload or loading until page is loaded completely?

南笙酒味 提交于 2019-12-02 18:30:19

# UPDATE [August 2017]

Same answer as below except we could work with the load event on window instead of DOMContentLoaded on document. This will ensure that all assets (such as images) in the window are loaded.

window.addEventListener("load", function(event) {
    ...
})

We don't have to force Angular where vanilla javascript can suffice. This is how it worked for my AngularJS project

Added this to the body tag. It will be removed with a script tag once HTML Content Loads

<div id="page-loading">
    <img style="display:block; margin:0 auto;" src="styles/img/page-loading.gif">
</div>

script tag right under the image.

<script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function(event) {
        /*VANILLA JAVASCRIPT*/
        var element = document.getElementById("page-loading");
        element.parentNode.removeChild(element);
        /* OR WITH jQuery*/
        $('#page-loading')
            .fadeOut('slow');
    });
</script>

DOMContentLoaded event will ensure that the the callback is executed when all the images,fonts,js and other assets have been loaded.

Good Luck.

Haseeb Ahmed

I'm not sure if this is the right approach, but what I usually do is that I have a $scope.loaded variable which has the state of the page. If the page is loaded, the div you want to show is shown... If it's loading, the div with the loader is shown. Have a look at this plunk to get what I'm trying to say.

I'm pasting the Plunkr code here as well.

Javascript

  var app = angular.module('plunker', []);

  app.controller('MainCtrl', function($scope, $timeout) {
    $scope.loaded = true;
    $scope.text = 'Nothing loaded yet.';

    $scope.loadSomething = function () {
      $scope.loaded = false;

      $timeout(function() {
        // Simulates loading
        $scope.text = 'Hello World';
        $scope.loaded = true;
      }, 2000);
    };
  });

HTML

<body ng-controller="MainCtrl">
<button class="btn btn-primary" ng-click="loadSomething()">Load Something</button>
<br/>
<div ng-hide="loaded">
  Loading...
</div>
<div ng-show="loaded">
  <p>{{ text }}</p>
</div>

Do let me know if you need any further help.

Try this:

angular.element($window).bind('load', function() {
 $scope.yourLoaderDiv=true;
});

I have struggled with same issue. Here is what working on my side where i am showing multiple loading image for each different section based on promise. For this purpose i have created a directive.

My html looks something like below.

<mi-loading promise="Loading"></mi-loading>

Angularjs directive.

(function () {

    var module = angular.module('mi-loading', []);

    module.directive('miLoading', function () {
        return {
            restrict: 'E',
            scope: {
                promise: '='
            },

            link: function ($scope, $element, $attrs) {

                $scope.IsLoading = true;

                $scope.$watch('promise', function (prom) {
                    if (!prom) {
                        $scope.IsLoading = false;
                        return;
                    }
                    prom.success(function () { $scope.IsLoading = false; });
                });
            },
            template: '<div ng-show="IsLoading" class="spinner" style="height:300px"></div>'
        };
    });

})();

and finally the usage,

 var getData = function ()
           {
               var Promise = myservice.getMyData($scope);

               $scope.Loading = Promise;
           };

CSS

.spinner {
    min-width: 30px;
    min-height: 30px;
}

    .spinner:before {
        content: 'Loading…';
        position: absolute;
        top: 50%;
        left: 50%;
        width: 24px;
        height: 24px;
        margin-top: -13px;
        margin-left: -13px;
    }

    .spinner:not(:required):before {
        content: '';
        border-radius: 50%;
        border: 3px solid #ccc;
        /*border-top-color: #03ade0;*/
        border-top-color: #4187b5;
        animation: spinner .6s linear infinite;
        -webkit-animation: spinner .6s linear infinite;
    }

To achieve it, i am loading all my scripts at the end of the body. Before my app-wrapper-div i place a postion fixed "loading"-div. It is shown immediately before other scripts are loaded.

At the end of the body, after my scripts are included, i place an angular directive, that fadeOut and remove the loading-div.

The code:

<html ng-app="myApp">
<head>
  <!-- the only file loaded in the head -->
  <link rel="stylesheet" href="/.../appLoadingScreen.css"/>
</head>
<body>
    <div id="appLoadingScreen">
      <div id="appLoadingScreenCenterWrap">
        <h1 id="appLoadingScreenHeader">APP TITLE</h1>
        <p id="appLoadingScreenMsg">App is loading!</p>
      </div>
    </div>
    <div id="appWrapper" ng-controller="appCtrl"> 
    ... 
    </div>
    <!-- All stylesheet includes -->
    ...
    <!-- All script includes -->
    ...
    <script src="/.../hideLoadingScreen.js"></script>
    <hide-loading-screen></hide-loading-screen>
</body>
</html>

And the hideLoadingScreen directive:

(function() {
  var app = angular.module('appModule');
  app.directive('hideLoadingScreen', function($timeout) {
    return {
      restrict: 'E',
      link: function() {
        $timeout(function() {
          $("#appLoadingScreen").fadeOut(600, function(){$(this).remove();});
        }, 400);
      }
    };
  });
})();
terales

While @chotesah answer is just right I can suggest you go another way and use preloaders for each image (something like Facebook on page load).

Try this module. You'll need to change few lines:

// Add module dependency   
angular.module('app', ['angular-preload-image']);
…
<img preload-image idx="id-thumb-{{$index}}" ng-src="/imagedisplay/{{image.imageid}}" default-image="[URL]" fallback-image="[URL]" />

After that look for nifty image preloaders at codrops.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!