Reputation:
I am new to Angular 6 and no experience in any version of angular previously & creating my website using angular 6, in which i have to display spinner till API Response is pending.I am using httpclient of angular 6 to call APIs. I want to show spinner for every API request. I searched on SO but didn't find answer of my question.Below is my component & services file.
/* data.services.ts */
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
getUsers() {
return this.http.get('https://jsonplaceholder.typicode.com/users')
}
}
/* users.component.ts *
import { Component, OnInit } from '@angular/core';
import {DataService} from '../data.service';
import { Observable } from 'rxjs';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
users$: Object;
constructor(private data: DataService) { }
ngOnInit() {
this.data.getUsers().subscribe(data => {
this.users$ = data;
});
}
}
Note: I don't want to use any package or module for that.
Can anyone please help me to solve this problem? Any help would be appreciated.
Upvotes: 10
Views: 47234
Reputation: 3714
You could store a reference on the subscription as a users component property, then use a simple *ngIf in your template to show/hide the loading indicator :
/* users.component.ts *
import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';
import { Observable, Subscription } from 'rxjs';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
users$: Object;
subscription: Subscription
constructor(private data: DataService) { }
ngOnInit() {
this.subscription = this.data.getUsers().subscribe(data => {
this.users$ = data;
});
}
}
In your template:
...
<div *ngIf="!subscription?.closed">loading...</div>
...
See http://reactivex.io/rxjs/class/es6/Subscription.js~Subscription.html for more infos on Subscription class.
It's beyond this question scope but you also should check that your subscription is closed when your component is destroyed (so keeping a reference on the subscription can help): call subscription.unsubscribe() if necessary in ngOnDestroy() for example, or extend from a base class for this purpose (so all of your components could benefit from it).
See https://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/ or https://netbasal.com/automagically-unsubscribe-in-angular-4487e9853a88
Upvotes: 1
Reputation: 2416
For that purpose I would use http interceptor for checking certain events during http request. Let's have component which will have some loader and put that component on same level like router outlet or app component. From our interceptor we will communicate with service to tell our component whenever show loader or not.
There is simple angular 6 example for that: https://stackblitz.com/edit/angular-hgxcsu
Upvotes: 2
Reputation: 21638
If you insist on not installing any packages then use a boolean flag to tell if the loading has finished yet
Get a loading animation from https://loading.io/ to put in the loading section of the html
/* data.services.ts */
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
getUsers() {
return this.http.get('https://jsonplaceholder.typicode.com/users')
}
}
/* users.component.ts *
import { Component, OnInit } from '@angular/core';
import {DataService} from '../data.service';
import { Observable } from 'rxjs';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
users: Object; // <-- Do not use $ at the end of a variable unless it is an observable
loading = true;
constructor(private data: DataService) { }
ngOnInit() {
this.data.getUsers().subscribe(data => {
this.users = data;
this.loading = false;
});
}
}
<div *ngIf="loading else loaded">
loading ...
</div>
<ng-template #loaded>
<div *ngFor="let user of users">{{user.name}}</div>
</ng-template>
Upvotes: 13
Reputation: 21638
Take a look at my package ngx-RxCache. Dealing with loading is one of the key use cases. Install ngx-rxcache. Don't subscribe to observables in your TypeScript, use the async pipe in your view. Check out a demo at https://stackblitz.com/edit/angular-3yqpfe
Get a loading animation from https://loading.io/ to put in the loading section of the html
/* data.services.ts */
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { RxCacheService } from 'ngx-rxcache';
import { User } from 'path to user interface definition';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient, private cache: RxCacheService) { }
load() {
this.usersCacheItem.load();
}
private usersCacheItem = this.cache.get<User[]>({
id: '[User] users',
construct: () => this.http.get<User[]>('https://jsonplaceholder.typicode.com/users')
});
users$ = this.usersCacheItem.value$;
loading$ = this.usersCacheItem.loading$;
}
/* users.component.ts *
import { Component, OnInit } from '@angular/core';
import {DataService} from '../data.service';
import { Observable } from 'rxjs';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
users$: this.data.users$;
loading$: this.data.loading$;
constructor(private data: DataService) {
data.load();
}
}
<div *ngIf="loading$ | async; else loaded">
loading ...
</div>
<ng-template #loaded>
<div *ngFor="let user of users$ | async">{{item}}</div>
</ng-template>
Upvotes: 0
Reputation: 12036
You can use ng4-loading-spinner
Execute npm i ng4-loading-spinner --save
Import module to your application root module
import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
Make an import entry
imports: [ Ng4LoadingSpinnerModule.forRoot() ]
Include spinner component to your root level component.
<ng4-loading-spinner> </ng4-loading-spinner>
use show()
and hide()
inside subscribe
callback
import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
constructor(
private spinnerService: Ng4LoadingSpinnerService,
private data: DataService
) { }
ngOnInit() {
this.spinnerService.show();//show the spinner
this.data.getUsers().subscribe(data => {
this.users$ = data;
this.spinnerService.hide();//hide the spinner if success
},
(error)=>this.spinnerService.hide();//hide the spinner in case of error
);
}}
Upvotes: 2