Angular Router Guards を使って読み込み画面を表示
Angular 2 でルート遷移時に読み込み画面を表示する方法
Angular 2 でルート間をナビゲートするときに読み込み画面を表示することは、ユーザーエクスペリエンスを向上させるために役立ちます。ユーザーが新しいページに移動していることを示し、ページの読み込みを待っている間に気を紛らわせることができます。
この機能を実装するには、いくつかの方法があります。ここでは、2つの一般的な方法をご紹介します。
Angular Router Guards を使用すると、ルート変更を遮断し、読み込み画面を表示することができます。
まず、AuthGuard
サービスを作成する必要があります。このサービスは、canActivate
メソッドを持つ必要があります。このメソッドは、ルート変更を許可するかどうかを決定します。
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
@Injectable()
export class LoadingGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(): boolean {
// 読み込み画面を表示
this.showLoading();
// 非同期処理を実行
// ...
// 読み込み画面を非表示
this.hideLoading();
// すべてのルート変更を許可
return true;
}
private showLoading() {
// 読み込み画面を表示するロジック
}
private hideLoading() {
// 読み込み画面を非表示にするロジック
}
}
次に、AppRoutingModule
で AuthGuard
を使用する必要があります。
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoadingGuard } from './loading.guard';
const routes: Routes = [
{ path: '', component: HomeComponent, canActivate: [LoadingGuard] },
{ path: 'about', component: AboutComponent, canActivate: [LoadingGuard] },
// ...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoadingGuard]
})
export class AppRoutingModule { }
RxJS Observables を使用すると、非同期処理が完了するまでルート変更を遅らせることができます。
まず、LoadingService
サービスを作成する必要があります。このサービスは、showLoading
と hideLoading
メソッドを持つ Observable を提供する必要があります。
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable()
export class LoadingService {
private loadingSubject = new Subject<boolean>();
loading$ = this.loadingSubject.asObservable();
showLoading() {
this.loadingSubject.next(true);
}
hideLoading() {
this.loadingSubject.next(false);
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoadingService } from './loading.service';
const routes: Routes = [
{ path: '', component: HomeComponent, resolve: { loading: LoadingService } },
{ path: 'about', component: AboutComponent, resolve: { loading: LoadingService } },
// ...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoadingService]
})
export class AppRoutingModule { }
最後に、各ルートコンポーネントで LoadingService
を注入し、ngOnInit
メソッドで showLoading
と hideLoading
メソッドを呼び出す必要があります。
import { Component, OnInit, Inject } from '@angular/core';
import { LoadingService } from '../loading.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(@Inject(LoadingService) private loadingService: LoadingService) { }
ngOnInit() {
this.loadingService.showLoading();
// 非同期処理を実行
// ...
this.loadingService.hideLoading();
}
}
これらの方法はどちらも、Angular 2 でルート遷移時に読み込み画面を表示する方法を提供します。どちらの方法を使用するかは、個々の要件によって異なります。
補足
- 読み込み画面のデザインは、CSS で自由にカスタマイズできます。
- 読み込み画面を表示するかどうかを制御するために、追加
Angular Router Guards を使用する
// loading.guard.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
@Injectable()
export class LoadingGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(): boolean {
// 読み込み画面を表示
this.showLoading();
// 非同期処理を実行
// ...
// 読み込み画面を非表示
this.hideLoading();
// すべてのルート変更を許可
return true;
}
private showLoading() {
// 読み込み画面を表示するロジック
// 例:
const loadingElement = document.getElementById('loading');
loadingElement.style.display = 'block';
}
private hideLoading() {
// 読み込み画面を非表示にするロジック
// 例:
const loadingElement = document.getElementById('loading');
loadingElement.style.display = 'none';
}
}
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoadingGuard } from './loading.guard';
const routes: Routes = [
{ path: '', component: HomeComponent, canActivate: [LoadingGuard] },
{ path: 'about', component: AboutComponent, canActivate: [LoadingGuard] },
// ...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoadingGuard]
})
export class AppRoutingModule { }
// home.component.html
<div class="container">
<h1>Home</h1>
<div *ngIf="loadingService.loading$ | async">
<div id="loading">
<p>読み込み中...</p>
</div>
</div>
</div>
// home.component.ts
import { Component, OnInit, Inject } from '@angular/core';
import { LoadingService } from '../loading.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(@Inject(LoadingService) private loadingService: LoadingService) { }
ngOnInit() {
this.loadingService.showLoading();
// 非同期処理を実行
// ...
this.loadingService.hideLoading();
}
}
// loading.service.ts
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable()
export class LoadingService {
private loadingSubject = new Subject<boolean>();
loading$ = this.loadingSubject.asObservable();
showLoading() {
this.loadingSubject.next(true);
}
hideLoading() {
this.loadingSubject.next(false);
}
}
RxJS Observables を使用する
// loading.service.ts
import { Injectable } from '@angular/core';
import { Observable, of, delay } from 'rxjs';
@Injectable()
export class LoadingService {
showLoading() {
return of(true).pipe(delay(500)); // 読み込み画面を500ミリ秒表示
}
hideLoading() {
return of(false);
}
}
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoadingService } from './loading.service';
const routes: Routes = [
{ path: '', component: HomeComponent, resolve: { loading: LoadingService } },
{ path: 'about', component: AboutComponent, resolve: { loading: LoadingService } },
// ...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoadingService]
})
export class AppRoutingModule { }
// home.component.html
<div class="container">
<h1>Home</h1>
<div *ngIf="loading">
<div id="loading">
<p>読み込み中...</p>
</div>
</div>
</div>
// home.component.ts
import { Component, OnInit, Inject } from '@angular
以下は、Angular 2 でルート遷移時に読み込み画面を表示するその他の方法です。
まず、RouterEventsService
サービスを作成する必要があります。このサービスは、routeChange
イベントを発行する必要があります。
import { Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
@Injectable()
export class RouterEventsService {
routeChange$ = new Subject<NavigationEnd>();
constructor(private router: Router) {
this.router.events.subscribe((event: any) => {
if (event instanceof NavigationEnd) {
this.routeChange$.next(event);
}
});
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RouterEventsService } from './router-events.service';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
// ...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [RouterEventsService]
})
export class AppRoutingModule { }
最後に、各ルートコンポーネントで RouterEventsService
を注入し、ngOnInit
メソッドで routeChange$
Observable を購読し、読み込み画面を表示する必要があります。
import { Component, OnInit, Inject } from '@angular/core';
import { RouterEventsService } from '../router-events.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(@Inject(RouterEventsService) private routerEventsService: RouterEventsService) { }
ngOnInit() {
this.routerEventsService.routeChange$.subscribe((event: NavigationEnd) => {
this.loadingService.showLoading();
// 非同期処理を実行
// ...
this.loadingService.hideLoading();
});
}
}
Ngrx/Store を使用すると、読み込み画面の状態を管理し、ルート遷移時に読み込み画面を表示することができます。
まず、LoadingState
という名のStore sliceを作成する必要があります。
import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
export enum LoadingActionTypes {
SHOW_LOADING = '[Loading] Show Loading',
HIDE_LOADING = '[Loading] Hide Loading',
}
export class ShowLoadingAction implements Action {
readonly type = LoadingActionTypes.SHOW_LOADING;
}
export class HideLoadingAction implements Action {
readonly type = LoadingActionTypes.HIDE_LOADING;
}
const initialState = {
loading: false,
};
@Injectable()
export class LoadingReducer {
constructor() {}
reduce(state = initialState, action: LoadingAction) {
switch (action.type) {
case LoadingActionTypes.SHOW_LOADING:
return { ...state, loading: true };
case LoadingActionTypes.HIDE_LOADING:
return { ...state, loading: false };
default:
return state;
}
}
}
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { loadingReducer } from './reducers/loading.reducer';
@NgModule({
imports: [StoreModule.forRoot({ loading: loadingReducer })],
exports: [StoreModule],
})
export class AppRoutingModule { }
最後に、各ルートコンポーネントで Store
を注入し、ngOnInit
メソッドで select
メソッドを使用して loading
ステートを購読し、読み込み画面を表示する必要があります。
import { Component, OnInit, Inject } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { AppState } from '../app.state';
@Component({
selector: 'app-home',
templateUrl
html css angular