Angular2: Using custom loader / spinner as service in Angular 2 application

Standard

Since loaders/spinners are essential component for any connected web application, we have couple of spinner component available in market for angular2. For spinner’s css, I am using Absolute Center CSS Overlay Spinner By MattIn4D

Usage

Since spinner is used throughout the application, so its better to define it once in index.html and then try to enable/disable through component code. I am also using BehaviorSubject object in service, which is way more awesome and better then observable in many cases, Behavior Subject is a special type of observable so you can subscribe to messages like any other observable. In plain words the variable controlling enabling and disabling the spinner in index.html can be set and observed in service using BehaviorSubject object.

Step 1 : Copy spinner css IN app.component.css file:

.tootlbar-icon {
  padding: 0 14px;
}

.tootlbar-spacer {
  flex: 1 1 auto;
}

/* Absolute Center Spinner */
.loading {
  position: fixed;
  z-index: 999;
  height: 2em;
  width: 2em;
  overflow: show;
  margin: auto;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}

/* Transparent Overlay */
.loading:before {
  content: '';
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.3);
}

/* :not(:required) hides these rules from IE9 and below */
.loading:not(:required) {
  /* hide "loading..." text */
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
  background-color: transparent;
  border: 0;
}

.loading:not(:required):after {
  content: '';
  display: block;
  font-size: 10px;
  width: 1em;
  height: 1em;
  margin-top: -0.5em;
  -webkit-animation: spinner 1500ms infinite linear;
  -moz-animation: spinner 1500ms infinite linear;
  -ms-animation: spinner 1500ms infinite linear;
  -o-animation: spinner 1500ms infinite linear;
  animation: spinner 1500ms infinite linear;
  border-radius: 0.5em;
  -webkit-box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
  box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0, rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
}

/* Animation */

@-webkit-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-moz-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-o-keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes spinner {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -o-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

Step 2 : Create angular material spinner service IN loader.service.ts:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class LoaderService {
    public status: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

    display(value: boolean) {
        this.status.next(value);
    }
}

Step 3: Register loader service to main module IN app.module.ts:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { MaterialModule } from '@angular/material';
import 'node_modules/hammerjs/hammer.js';

import { AppComponent } from './app.component';
import { CustomComponent } from './custom.component';
import { LoaderService } from './shared/service/loader.service';

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,

        //ui module
        MaterialModule.forRoot()
    ],
    declarations: [
        AppComponent,
        CustomComponent 
    ],
    providers: [
        LoaderService
    ],
    bootstrap: [
        AppComponent
    ],
    schemas: [
        CUSTOM_ELEMENTS_SCHEMA
    ]
})

export class AppModule {
}

Step 4 : Register spinner html inside router-outlet to have its impact on all components IN app.component.html

<router-outlet>
    <span*ngIf="showLoader" class="loading"></span>
</router-outlet>
*wordpress text editor has issue with div tag, you can replace span with tag

Step 5: Inject toaster service inside app.component.ts to show or hide loader

import { Component, OnInit } from '@angular/core';

import { LoaderService } from './shared/service/loader.service';

@Component({
    selector: 'my-app',
    templateUrl: './app/app.component.html',
    styleUrls: ['./app/app.component.css']
})

export class AppComponent implements OnInit {
    showLoader: boolean;

    constructor(
        private loaderService: LoaderService) {
    }

    ngOnInit() {
        this.loaderService.status.subscribe((val: boolean) => {
            this.showLoader = val;
        });
    }
}

Step 6: Consume loader service in controller custom.component.ts:

Just pass ‘true’ in order to display the loader and ‘false’ in order to hide the loader

import { Component, OnInit } from '@angular/core';
import { LoaderService } from '../loader.service';

@Component({
    selector: 'search-movie',
    templateUrl: '../custom.component.html'
})

export class CustomComponent implements OnInit {

    constructor(
        private loaderService: LoaderService) {
    }

    ngOnInit() {
        //http call starts
        this.loaderService.display(true);
        //http call ends
        this.loaderService.display(false);
    }
}

Output:

 

6 thoughts on “Angular2: Using custom loader / spinner as service in Angular 2 application

Leave a comment