dark_shadow
dark_shadow

Reputation: 3573

Spinner in Angular.js

I want to use a spinner which I can show during some of the rest api calls for a better UX. I have come across many existing github projects which does exactly similar things.

https://github.com/cgross/angular-busy
https://github.com/urish/angular-spinner

But I'm not able to use any of the existing projects. I think before I start writing something of my own, I want to know if things which I'm looking for can be done using these projects or any other existing project.

Requirement:

  1. During some of the rest api calls like uploading images, fetching some data, deleting images, etc, I want to show a spinner with background faded. Once I have the result, I can show the background again and remove the spinner.
  2. I want to use this spinner with start/stop from my controller not from my html.
  3. I don't want this spinner for all the xhr requests by default.

I think angular-busy demo does solves most of the above requirements except that it needs a promise param in html. Is there anyway by which I can control the start/stop dynamically from my controller rather than giving a promise.

Angular-spinner demo is good but it doesn't fade out background. Is there any way to fade out background ?

Can anyone give me some pointers how exactly can I solve my problem ?

Upvotes: 2

Views: 4699

Answers (2)

Bsalex
Bsalex

Reputation: 2970

It seems like http://bsalex.github.io/angular-loading-overlay/_site/ fits the requirements.

For example:

var app = angular.module('app-http-integration-with-reference-id-and-matchers', [
    'bsLoadingOverlay',
    'bsLoadingOverlayHttpInterceptor'
  ])
  .factory('randomTextInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
    return bsLoadingOverlayHttpInterceptorFactoryFactory({
      referenceId: 'random-text-spinner',
      requestsMatcher: function(requestConfig) {
        return requestConfig.url.indexOf('hipsterjesus') !== -1;
      }
    });
  })
  .factory('randomUserInterceptor', function(bsLoadingOverlayHttpInterceptorFactoryFactory) {
    return bsLoadingOverlayHttpInterceptorFactoryFactory({
      referenceId: 'random-user-spinner',
      requestsMatcher: function(requestConfig) {
        return requestConfig.url.indexOf('randomuser') !== -1;
      }
    });
  })
  .config(function($httpProvider) {
    $httpProvider.interceptors.push('randomTextInterceptor');
    $httpProvider.interceptors.push('randomUserInterceptor');
  }).run(function($sce, bsLoadingOverlayService) {
    bsLoadingOverlayService.setGlobalConfig({
      /* 
          It is only an example, don't use this url in production.
          Copy this template to your code base or use integration with Spin.js (see Docs & Examples)
      */
      templateUrl: $sce.trustAsResourceUrl('https://raw.githubusercontent.com/bsalex/angular-loading-overlay/gh-pages/_site/loading-overlay-template.html')
    });
  });

app.controller('HttpIntegrationWithReferenceIdAndMatchersController', function($scope, $http, $sce, bsLoadingOverlayService) {
  $scope.randomText = $sce.trustAsHtml('Fetch result here');
  $scope.randomUser = undefined;

  $scope.fetchRandomText = function() {
    $http.get('http://hipsterjesus.com/api/')
      .success(function(data) {
        $scope.randomText = $sce.trustAsHtml(data.text);
      })
      .error(function() {
        $scope.randomText = $sce.trustAsHtml('Can not get the article');
      });
  };

  $scope.fetchRandomUser = function() {
    $http.get('https://randomuser.me/api/')
      .success(function(data) {
        $scope.randomUser = data.results[0];
      });
  };
});
.random-result {
  display: flex;
  height: 170px;
  margin-top: 1em;
}
.random-result__text,
.random-result__user {
  position: relative;
  overflow: auto;
  border: 2px dashed #C00;
  flex: 1;
  margin: 0.5em;
  padding: 0.5em;
  text-align: center;
}
.user__photo {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin: 0;
}
.user__name {
  font-size: 1.5em;
  margin: 0.5em;
  padding: 0;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="https://rawgit.com/bsalex/angular-loading-overlay/master/dist/angular-loading-overlay.js"></script>
<script src="https://rawgit.com/bsalex/angular-loading-overlay-http-interceptor/master/dist/angular-loading-overlay-http-interceptor.js"></script>
<div ng-app="app-http-integration-with-reference-id-and-matchers">
  <div ng-controller="HttpIntegrationWithReferenceIdAndMatchersController">
    <div class="well well-lg bs-loading-container">
      <button ng-click="fetchRandomText()">Fetch random text</button>
      <button ng-click="fetchRandomUser()">Fetch random user</button>
      <div class="random-result">
        <div class="random-result__text" bs-loading-overlay bs-loading-overlay-reference-id="random-text-spinner" bs-loading-overlay-delay="3000">
          <p ng-bind-html="randomText"></p>
        </div>
        <div class="random-result__user user" bs-loading-overlay bs-loading-overlay-reference-id="random-user-spinner" bs-loading-overlay-delay="3000">
          <div ng-if="randomUser">
            <img ng-src="{{randomUser.picture.large}}" alt="" class="user__photo" />
            <p class="user__name">
              {{randomUser.name.first}} {{randomUser.name.last}}
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

In the snippet above I've used integration with $http service. It matches requests and shows spinner with specified referenceId.

Also, the following features are available:

  • You can show and hide spinners from controllers injecting bsLoadingOverlayService and calling bsLoadingOverlayService.start(); and bsLoadingOverlayService.stop();;
  • You can wrap Promises to show and hide spinners with bsLoadingOverlayService.wrap();
  • You can create preconfigured handlers (bsLoadingOverlayService.createHandler({referenceId: 'handler-overlay'});), to keep options in one place and then just call preconfiguredHandler.start(); and preconfiguredHandler.stop();

Upvotes: 1

Oren Haliva
Oren Haliva

Reputation: 351

I always create my own spinner with this logic:

js:

app.directive('ngSpinnerBar', ['$rootScope',
    function ($rootScope) {
        return {
            link: function (scope, element, attrs) {
                // by defult hide the spinner bar
                element.addClass('hide'); 

                // count how many time requests were sent to the server
                // so when they all done the spinner will be removed
                scope.counter = 0;

                $rootScope.$on('$stateNetworkRequestStarted', function () {
                    scope.counter++;
                    element.removeClass('hide'); // show spinner bar
                    //  $('body').addClass('page-on-load');
                });

                $rootScope.$on('$stateNetworkRequestEnded', function () {
                    scope.counter--;
                    if (scope.counter <= 0) {
                        scope.counter = 0;
                        element.addClass('hide'); // show spinner bar
                        //  $('body').removeClass('page-on-load'); // remove page loading indicator
                    }

                });

            }
        };
    }
])

html:

<div ng-spinner-bar></div>

As you can see every time i send a request to the api i show the spinner (css create the spinning - link) and when result come back i send event to hide the spinner.

if you want to make things easier for you, you should create a service which send all the api requests (wrap $http). that way you can ensure every request will show the spinner.

EDIT

the first result in google gave me this - fade background in angular

Upvotes: 2

Related Questions