Menambahkan Loading Spinner
KIta akan menambahkan candy dengan menampilkan loading spinner. Anda dapat gunakan free loading spinner dari https://loading.io/css.
Buat file baru untuk component spinner, shared/loading-spinner/loading-spinner.component.ts dan loading-spinner.component.css.
File loading-spinner.component.css
.lds-facebook { display: inline-block; position: relative; width: 80px; height: 80px; } .lds-facebook div { display: inline-block; position: absolute; left: 8px; width: 16px; background: rgb(184, 0, 0); animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite; } .lds-facebook div:nth-child(1) { left: 8px; animation-delay: -0.24s; } .lds-facebook div:nth-child(2) { left: 32px; animation-delay: -0.12s; } .lds-facebook div:nth-child(3) { left: 56px; animation-delay: 0; } @keyframes lds-facebook { 0% { top: 8px; height: 64px; } 50%, 100% { top: 24px; height: 32px; } }
File loading-spinner.component.ts
import { Component } from "@angular/core"; @Component({ selector: 'app-loading-spinner', template: '<div class="lds-facebook"><div></div><div></div><div></div></div>', styleUrls: ['./loading-spinner.component.css'] }) export class LoadingSpinnerComponent{ }
Kemudian registrasikan pada app.module.ts
import { NgModule} from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import {FormsModule, ReactiveFormsModule } from '@angular/forms'; import {HttpClientModule} from '@angular/common/http'; import { AppComponent } from './app.component'; import { HeaderComponent } from './header/header.component'; import { RecipesComponent } from './recipes/recipes.component'; import { RecipeListComponent } from './recipes/recipe-list/recipe-list.component'; import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component'; import { RecipeItemComponent } from './recipes/recipe-list/recipe-item/recipe-item.component'; import { ShoppingListComponent } from './shopping-list/shopping-list.component'; import { ShoppingEditComponent } from './shopping-list/shopping-edit/shopping-edit.component'; import { DropDownDirective } from './shared/dropdown.directive'; import { ShoppingListService } from './shopping-list/shopping-list.service'; import { AppRoutingModule } from './app-routing.module'; import { RecipeHomeComponent } from './recipes/recipe-home/recipe-home.component'; import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component'; import { RecipeService } from './recipes/recipe.service'; import { AuthComponent } from './auth/auth.component'; //tambahkan file LoadingSpinnerComponent jika IDE tidak otomatis. import { LoadingSpinnerComponent } from './shared/loading-spinner/loading-spinner.component'; @NgModule({ declarations: [ AppComponent, HeaderComponent, RecipesComponent, RecipeListComponent, RecipeDetailComponent, RecipeItemComponent, ShoppingListComponent, ShoppingEditComponent, DropDownDirective, RecipeHomeComponent, RecipeEditComponent, AuthComponent, LoadingSpinnerComponent //registrasi loading spinner ], imports: [ BrowserModule, FormsModule, ReactiveFormsModule, HttpClientModule, AppRoutingModule ], providers: [ShoppingListService, RecipeService], bootstrap: [AppComponent] }) export class AppModule { }
Buka file auth.component.ts, tambahkan property untuk status loading.
import { Component } from "@angular/core"; import { NgForm } from "@angular/forms"; import { AuthService } from "./auth.service"; @Component({ selector : 'app-auth', templateUrl : './auth.component.html' }) export class AuthComponent{ isLoginMode = true; //property untuk status loading data isLoading = false; constructor(private authSrv : AuthService){} onSwitchMode(){ this.isLoginMode = !this.isLoginMode; } onSubmit(form : NgForm){ if (form.invalid){ return; } const email = form.value.email; const pswrd = form.value.password; //ubah property loading saat melakukan request. this.isLoading = true; if(this.isLoginMode){ // }else{ this.authSrv.signUp(email, pswrd).subscribe(respData =>{ console.log(respData); //ubah property loading false setelah selesai request this.isLoading = false; }, error =>{ console.log(error); //ubah property loading false setelah selesai request this.isLoading = false; }); } form.reset() } }
Kemudian kita gunakan property tersebut pada auth.component.html
KIta gunakan ngIf untuk propery isLoading, jika true, kita tampilkan spinne dan sembunyikan form.
<div class="row"> <div class="col-xs-12 col-md-6 col-md-offset-3"> <!-- menambahkan loading spinner --> <div *ngIf="isLoading"> <app-loading-spinner></app-loading-spinner> </div> <form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)" *ngIf="!isLoading"> <div class="form-group"> <label for="email">Email</label> <input type="email" id="email" class="form-control" ngModel name="email" required email> </div> <div class="form-group"> <label for="password">Password</label> <input type="password" id="password" class="form-control" ngModel name="password" required minlength="6"> </div> <hr> <div> <button class="btn btn-primary" type="submit" [disabled]="loginForm.invalid">{{isLoginMode ? 'Login' : 'Signup'}}</button> <button class="btn btn-primary" (click)="onSwitchMode()" type="button">Switch to {{isLoginMode ? 'Signup' : 'Login'}}</button> </div> </form> </div> </div>

Menambahkan Error Message
Selanjutnya kita juga akan menampilkan error message. Salah satu error yang mungkin terjadi email yang sama digunakan untuk signup.
Buka file auth.service.ts, lalu tambahkan method pipe untuk melakukan Catch Error.
import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import { catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; interface AuthResponse { idToken: string; email: string; refreshToken: string; expiresIn: string; localId: string; } @Injectable({providedIn: 'root'}) export class AuthService { constructor(private http: HttpClient){ } signUp(email: string, pswrd: string){ return this.http .post<AuthResponse>('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyAHq81IV8SqS_n6KL9wEmuB_qs3_8J4szU', { email: email, password: pswrd, returnSecureToken: true } ) .pipe(catchError(errResp =>{ let errMsg = 'Unknown Error...'; if (!errResp.error || !errResp.error.error){ return throwError(errMsg); } switch(errResp.error.error.message){ case 'EMAIL_EXISTS': errMsg = 'Email sudah terdaftar'; } return throwError(errMsg); })) } }
Buka file auth.component.ts, lalu tambahkan property errorMsg, yang akan digunakan untuk menampilkan error message yang terjadi saat melakukan signup.
import { Component } from "@angular/core"; import { NgForm } from "@angular/forms"; import { AuthService } from "./auth.service"; @Component({ selector : 'app-auth', templateUrl : './auth.component.html' }) export class AuthComponent{ isLoginMode = true; isLoading = false; errorMsg = ''; constructor(private authSrv : AuthService){} onSwitchMode(){ this.isLoginMode = !this.isLoginMode; } onSubmit(form : NgForm){ if (form.invalid){ return; } const email = form.value.email; const pswrd = form.value.password; this.isLoading = true; this.errorMsg = ''; if(this.isLoginMode){ // }else{ this.authSrv.signUp(email, pswrd).subscribe(respData =>{ this.isLoading = false; }, errMsg =>{ this.errorMsg = errMsg; this.isLoading = false; }); } form.reset() } }
Buka file auth.component.html, lalu tambahkan ngIf untuk menampilkan error message.
<div class="row"> <div class="col-xs-12 col-md-6 col-md-offset-3"> <!-- menambahkan error message --> <div class="alert alert-danger" *ngIf="errorMsg != ''"> <p>{{errorMsg}}</p> </div> <div *ngIf="isLoading"> <app-loading-spinner></app-loading-spinner> </div> <form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)" *ngIf="!isLoading"> <div class="form-group"> <label for="email">Email</label> <input type="email" id="email" class="form-control" ngModel name="email" required email> </div> <div class="form-group"> <label for="password">Password</label> <input type="password" id="password" class="form-control" ngModel name="password" required minlength="6"> </div> <hr> <div> <button class="btn btn-primary" type="submit" [disabled]="loginForm.invalid">{{isLoginMode ? 'Login' : 'Signup'}}</button> <button class="btn btn-primary" (click)="onSwitchMode()" type="button">Switch to {{isLoginMode ? 'Signup' : 'Login'}}</button> </div> </form> </div> </div>
Sesuai ekspektasi, saat kita melakukan signup email yang sama, error message yang sesuai sudah ditampilkan.

Untuk error code, dapat diperoleh dari dokumentasi firebase di https://firebase.google.com/docs/reference/rest/auth#section-create-email-password
Sampai disini kita sudah berhasil melakukan signup dan melakukan error checking.
Pada modul selanjutnya kita akan melakukan proses signin.