Tutorial: Angular 10 CRUD Firestore Example – use @angular/fire: Post/get/delete/update query documents

Angular 10 Firestore CRUD Example

Tutorial: Angular 10 CRUD Firestore Example – use @angular/fire: Post/get/delete/update query documents

The Firestore is a cloud-hosted NoSQL database that lets you store and sync data between your users in realtime. We can structure data in our ways to improve querying and fetching capabilities. So in the tutorial, I introduce how to build an “Angular 10 CRUD Firestore Example” project with the help of @angular/fire lib to do CRUD operation: POST/GET/PUT/DELETE queries with step by step coding examples.

– I draw a fullstack overview diagram architecture from Angular frontend to Cloud Firestore.
– I illustrate details about @angular/fire CRUD operations.
– I implement Angular 10 CRUD application with the @angular/fire lib to do CRUD queries (Post/Get/Put/Delete document) to Cloud Firestore.

Related posts:


Overvier Architecture Diagram – Angular 10 CRUD Firestore Example use @angular/fire

Overall Architecture System: Angular 10 + Cloud Firestore

Angular 10 Firestore Diagram Architecture Integration
Angular 10 Firestore Diagram Architecture Integration

We use @angular/fire to integrate Angular Application with Firebase. Angular will use a service to do CRUD queries (post/get/put/delete document) with Cloud Firestore and show data on user-view through components.

Angular 10 CRUD Firestore Application Design

Angular 10 Diagram Architecture Design
Angular 10 Diagram Architecture Design

– Angular 10 CRUD Application is designed with 3 main layers:

  • Service Layer is used to do CRUD requests with Cloud Firestore
  • Component Layer is used to define Angular 10 Components to display views in Browser.
  • Router Layer is used to define all Angular navigation URLs mapping with the corresponding Angular Components
Angular 10 Firestore project structure
Angular 10 Firestore project structure

Angular CRUD Application defines 3 components, 2 services, 1 routers, and 2 data models:

– Angular Components:

  • add-customer component is used to post a new data to Firestore
  • list-customer component is used to display all data on views, delete a data and update a data with
    a given key to Firestore using @angular/fire
  • message component is used to define a view to show logging message on browser

– Angular Services:

  • customer.service.ts defines CRUD operation to post/get/put/delete requests to Cloud Firestore
  • message.service.ts defines an array storage to log all messages when the Angular 10 CRUD App running

– Angular Router: app-routing.module.ts defines how to map a corresponding Angular component with an URL.

– Models: customer.ts defines the main data model of Angular application.

Firestore CRUD queries with @angular/fire

Set up the Firebase Project & Install @angular/fire

To setup the integration between Angular and Firebase using @angular/fire, we follow step by step guides at the tutorial: Integrate Angular 10 + Firebase RealTime Database using @angular/fire

Register Firebase Successfully Get Firebase Script register Angular 10 Firestore integration - (Angular 10 + Firestore tutorial)
Register Firebase Successfully Get Firebase Script register Angular 10 Firestore integration – (Angular 10 + Firestore tutorial)

Firestore Object CRUD queries

To do CRUD queries with Firestore object, we use a set methods of interface AngularFirestoreDocument as below:

export declare class AngularFirestoreDocument<T = DocumentData> {
    ref: DocumentReference;
    private afs;
    /**
     * The contstuctor takes in a DocumentReference to provide wrapper methods
     * for data operations, data streaming, and Symbol.observable.
     */
    constructor(ref: DocumentReference, afs: AngularFirestore);
    /**
     * Create or overwrite a single document.
     */
    set(data: T, options?: SetOptions): Promise<void>;
    /**
     * Update some fields of a document without overwriting the entire document.
     */
    update(data: Partial<T>): Promise<void>;
    /**
     * Delete a document.
     */
    delete(): Promise<void>;
    /**
     * Create a reference to a sub-collection given a path and an optional query
     * function.
     */
    collection<R = DocumentData>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<R>;
    /**
     * Listen to snapshot updates from the document.
     */
    snapshotChanges(): Observable<Action<DocumentSnapshot<T>>>;
    /**
     * Listen to unwrapped snapshot updates from the document.
     */
    valueChanges(): Observable<T | undefined>;
    /**
     * Retrieve the document once.
     */
    get(options?: firestore.GetOptions): Observable<firestore.DocumentSnapshot<firestore.DocumentData>>;
}

– Firestoe create an Object binding/retrieve operation

item: AngularFirestoreDocument<any>;
// db: AngularFirestore
this.item = db.doc('item');
 
// or
Observable<any> item = db.doc('item').valueChanges();

– Firestore create Object operation

// db: AngularFirestore
const itemRef = db.doc('item');
 
// set() for destructive updates
itemRef.set({ name: 'loizenai'});

– Firestore Update Object operation

// db: AngularFirestore
const itemRef = db.doc('item');
itemRef.update({ url: 'loizenai.com'});

– Firestore Delete Object operation

// db: AngularFirestore
const itemRef = db.doc('item');
itemRef.delete();

Firestore List of Objects CRUD queries

To do CRUD queries with Firestore list, we use a set methods of interface AngularFirestoreCollection as below:

export declare class AngularFirestoreCollection<T = DocumentData> {
    readonly ref: CollectionReference;
    private readonly query;
    private readonly afs;
    /**
     * The constructor takes in a CollectionReference and Query to provide wrapper methods
     * for data operations and data streaming.
     *
     * Note: Data operation methods are done on the reference not the query. This means
     * when you update data it is not updating data to the window of your query unless
     * the data fits the criteria of the query. See the AssociatedRefence type for details
     * on this implication.
     */
    constructor(ref: CollectionReference, query: Query, afs: AngularFirestore);
    /**
     * Listen to the latest change in the stream. This method returns changes
     * as they occur and they are not sorted by query order. This allows you to construct
     * your own data structure.
     */
    stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of changes as they occur it time. This method is similar to stateChanges()
     * but it collects each event in an array over time.
     */
    auditTrail(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of synchronized changes. This method keeps the local array in sorted
     * query order.
     */
    snapshotChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Listen to all documents in the collection and its possible query as an Observable.
     *
     * If the `idField` option is provided, document IDs are included and mapped to the
     * provided `idField` property name.
     */
    valueChanges(): Observable<T[]>;
    valueChanges({}: {}): Observable<T[]>;
    valueChanges<K extends string>(options: {
        idField: K;
    }): Observable<(T & {
        [T in K]: string;
    })[]>;
    /**
     * Retrieve the results of the query once.
     */
    get(options?: firestore.GetOptions): Observable<firestore.QuerySnapshot<firestore.DocumentData>>;
    /**
     * Add data to a collection reference.
     *
     * Note: Data operation methods are done on the reference not the query. This means
     * when you update data it is not updating data to the window of your query unless
     * the data fits the criteria of the query.
     */
    add(data: T): Promise<DocumentReference>;
    /**
     * Create a reference to a single document in a collection.
     */
    doc<T>(path?: string): AngularFirestoreDocument<T>;
}

– Firestore Create a List Binding/ Retrieve query:

* It returns an Observable of data as a synchronized array of JSON objects without snapshot metadata. It is simple to render to a view:

items: Observable<any[]>;
// db: AngularFirestore
this.items = db.collection('items').valueChanges();

* Returns an Observable of data as a synchronized array of DocumentChangeAction<>[] with metadata (the underlying data reference and snapshot id):

items: Observable<any[]>;
// db: AngularFirestore
this.items = db.collection('items').snapshotChanges();

– Firestore Add Object operation to a List

// db: AngularFirestore
const itemsRef = db.collection('items');
itemsRef.add({ site: 'loizenai.com' });

– Firestore Update object operation in a List:

// set(): destructive update
// delete everything currently in place, then save the new value
const itemsRef = db.collection('items'); // db: AngularFirestore
itemsRef.doc(key).set({ url: 'lzai.com' });
 
// update(): non-destructive update
// only updates the values specified
const itemsRef = db.collection('items'); // db: AngularFirestore
itemsRef.doc(key).update({ url: 'loizenai.com' });

– Firestore Delete object operation

// db: AngularFirestore
const itemsRef = db.collection('items');
itemsRef.doc(key).delete();
 
// delete entire list
itemsRef.get().subscribe(
      querySnapshot => {
        querySnapshot.forEach((doc) => {
          doc.ref.delete();
        });
      },
      error => {
        console.log('Error: ', error);
      });

Implement Angular 10 CRUD Cloud Firestore using @angular/fire

Angular 10 CRUD Application Overview with Cloud Firestore

Angular 10 Diagram Architecture Design
Angular 10 Diagram Architecture Design

– For more details, we go back to the session: Angular CRUD Design

Create Angular 10 Application

We create Angular 10 CRUD project by commandline: ng new Angular10FirestoreCrud.

– Create 3 components AddCustomer, ListCustomers, Message by cmd:

ng g component AddCustomer
ng g component ListCustomers
ng g component Message

– Create 2 Angular services CustomerService, MessageService by cmd:

ng g service customer
ng g service message

– Create a model Customer by cmd: ng g class customer;

Add Firebase configuration to Angular environments variable

– Open /src/environments/environment.ts, add your Firebase configuration:

export const environment = {
  production: false,
  firebase: {
    apiKey: "AIzaSyBmeT3HEMFfjNmho1F5liOclLkjBNKJrmU",
    authDomain: "loizenai-firebase.firebaseapp.com",
    databaseURL: "https://loizenai-firebase.firebaseio.com",
    projectId: "loizenai-firebase",
    storageBucket: "loizenai-firebase.appspot.com",
    messagingSenderId: "887328809823"
  }
};
Register Firebase Successfully Get Firebase Script register Angular 10 Firestore integration - (Angular 10 + Firestore tutorial)
Register Firebase Successfully Get Firebase Script register Angular 10 Firestore integration – (Angular 10 + Firestore tutorial)

Setup Angular @NgModule with @angular/fire

Setup Angular @NgModule, open /src/app/app.module.ts, import AngularFireModule and other modules if necessary. Don’t forget specify Firebase configuration with AngularFireModule.initializeApp(firebaseConfig):

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
 
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule} from '@angular/fire/firestore';
import { environment } from '../environments/environment';
 
import { AppComponent } from './app.component';
...
 
@NgModule({
  declarations: [
    AppComponent
    ...
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFirestoreModule
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Create Angular Typescript Model

We define Customer class with 5 attributes:

export class Customer {
    key: string;
    firstname: string;
    lastname: string;
    age: number;
    address: string
}

Implement Angular 10 CRUD Firestore Service

For interacting with Cloud Firestore, we use @angular/fire AngularFirestore to implement a firestore crud queries (post/get/put/delete) service:

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { Customer } from './customer';
 
@Injectable({
  providedIn: 'root'
})
export class CustomerService {
 
  private dbPath = '/customers';
 
  customersRef: AngularFirestoreCollection<Customer> = null;
 
  constructor(private db: AngularFirestore) {
    this.customersRef = db.collection(this.dbPath);
  }
  ...
}

Angular Firestore Post request

  createCustomer(customer: Customer): void {
    this.customersRef.add({...customer});
  }

We use a method add(data: T): Promise<DocumentReference>; to post a data to Cloud Firestore.

Angular Firestore Get query

  getCustomersList(): AngularFirestoreCollection<Customer> {
    return this.customersRef;
  }

Angular Firestore Put query

  updateCustomer(key: string, value: any): Promise<void> {
    return this.customersRef.doc(key).update(value);
  }

Angular Firestore Delete query

  deleteCustomer(key: string): Promise<void> {
    return this.customersRef.doc(key).delete();
  }

Implement Angular post/get/put/delete components

Implement Angular Post Component: adding data

AddCustomerComponent is used to post a new data Customer to Cloud Firestore.

– We have 2 parts:

  • add-customer.component.ts file
  • add-cusomer.component.html file

1. add-customer.component.ts file

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-add-customer',
  templateUrl: './add-customer.component.html'
})
export class AddCustomerComponent implements OnInit {
  customer: Customer;
  /**
   * Constructing Http Customer Service
   * @param customerService 
   */
  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  ngOnInit(): void {
    this.customer = new Customer();
  }

  /**
   * Store a Customer to backend server
   */
  save() {
    try{

      this.customerService.createCustomer(this.customer);
      let msg = "Success -> Post a Customer: " 
                    + "<ul>"
                        + "<li>firstname: " + this.customer.firstname + "</li>"
                        + "<li>lastname: " + this.customer.lastname + "</li>"
                        + "<li>age: " + this.customer.age + "</li>"
                        + "<li>address: " + this.customer.address + "</li>"
                    + "</ul>";

      this.messageService.add(msg);
    } catch(err){
      console.error(err);
      let msg = "Error! -> Action Posting a Customer:" 
                  + "<ul>"
                    + "<li>firstname = " + this.customer.firstname + "</li>"
                    + "<li>lastname = " + this.customer.lastname + "</li>"
                    + "<li>age = " + this.customer.age + "</li>"
                    + "<li>address = " + this.customer.address + "</li>"
                  + "</ul>";

      this.messageService.add(msg);
    }
  }

  reset(){
    this.customer = new Customer();
  }

  /**
   * Function handles form submitting
   */
  onSubmit() {
    this.save();
    this.reset();
  }
}

2. Implement add-customer.component.html view:

<h2>Create Customer</h2>
<div>
  <form (ngSubmit)="onSubmit()"> 
    <!-- First name -->   
    <div class="form-group">
      <label for="firstname">First Name:</label>
      <input type="text" class="form-control" placeholder="Enter Firstname" 
                id="firstname" required [(ngModel)]="customer.firstname" name="firstname">
    </div>
    <!-- Last name -->
    <div class="form-group">
        <label for="lastname">Last Name:</label>
        <input type="text" class="form-control" placeholder="Enter Lastname" 
                  id="lastname" required [(ngModel)]="customer.lastname" name="lastname">
    </div>  
    <!-- Address -->
    <div class="form-group">
        <label for="address">Address:</label>
        <input type="text" class="form-control" placeholder="Enter Address" 
                  id="address" required [(ngModel)]="customer.address" name="address">
    </div>        
    
    <!-- Age -->
    <div class="form-group">
      <label for="age">Age</label>
      <input type="number" class="form-control" placeholder="Enter Age" 
                  id="age" required [(ngModel)]="customer.age" name="age">
    </div>
 
    <button type="submit" class="btn btn-success">Submit</button>
  </form>
</div>
<app-message></app-message>

Implement Angular List Component: retrieve all data

ListCustomersComponent has 4 main functions:

  • Show all Customers
  • Show details a Customers
  • Delete a Customer
  • Update a Customer

1. Implement list-customers.component.ts:

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { MessageService } from '../message.service';
import { CustomerService } from '../customer.service';

import { map } from 'rxjs/operators';

@Component({
  selector: 'app-list-customers',
  templateUrl: './list-customers.component.html'
})
export class ListCustomersComponent implements OnInit {

  customers: Array<Customer> = [];
  showCustomer: Customer;
  isSelected: boolean = false;
  deletedCustomer: Customer;
  returnedMessage: string;

  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  setCustomerDetails(customer: Customer){
    this.isSelected=!this.isSelected;
    if(this.isSelected){
      this.showCustomer = customer;
    }else{
      this.showCustomer = undefined;
    }
  }

  /**
   * Set deletedCustomer and reset returnedMessage = undefined
   * @param deleteCustomer
   */
  prepareDeleteCustomer(deleteCustomer: Customer){
    //assign delete-Customer
    this.deletedCustomer = deleteCustomer;
    // reset returned-Message
    this.returnedMessage = undefined;
  }

  /**
   * Delete a Customer by ID
   */
  deleteCustomer(){    
      this.customerService.deleteCustomer(this.deletedCustomer.key)
                .then(() => {
                  // remove a deletedCustomer from customers list on view
                  this.customers = this.customers.filter(customer => {
                    return customer.key != this.deletedCustomer.key;
                  })

                  // set a showing message in delete modal
                  this.returnedMessage = "Delete Successfully a Customer with key = " + this.deletedCustomer.key;

                  // just reset showCustomer for not showing on view
                  this.showCustomer = undefined;

                  // add the delete message to message app for showing
                  this.messageService.add(this.returnedMessage);
                })
                .catch(error => {
                  console.log(error);
                  let errMsg: string = "Error! Details: " + error;
                  this.messageService.add(errMsg);
                });
  }

  /**
   * Update Customer function
   */
  updateCustomer() {

    var updatedCustomer = Object.assign({}, this.showCustomer);
    delete updatedCustomer.key;

    this.customerService
      .updateCustomer(this.showCustomer.key, updatedCustomer)
                      .then(() => {
                          // update customers list
                          this.customers.map(x => {
                            if(x.key == this.showCustomer.key){
                              x = this.showCustomer;
                            }
                          });

                          let msg: string = "Update Successfully! -> New Customer's properties: <br>"
                                            + "<ul>"
                                              + "<li>" + "id: " + this.showCustomer.key + "</li>"
                                              + "<li>" + "firstname: " + this.showCustomer.firstname + "</li>"
                                              + "<li>" +  "lastname: " + this.showCustomer.lastname + "</li>"
                                              + "<li>" +  "age: " + this.showCustomer.age + "</li>"
                                              + "<li>" +  "address: " + this.showCustomer.address + "</li>"
                                            + "</ul>";
                          this.messageService.add(msg);
                      })
                      .catch(error => {
                        console.log(error);
                        let errMsg = "Update Fail ! Error = " + error;
                        this.messageService.add(errMsg);
                      });
  }

  /**
   * Retrieve all Customer from Backend
   */
  retrieveAllCustomers() {
    this.customerService.getCustomersList().snapshotChanges().pipe(
      map(changes =>
        changes.map(c =>
          ({ key: c.payload.key, ...c.payload.val() })
        )
      )
    ).subscribe(customers => {
      this.customers = customers;
    }, (error) => {
      console.log(error);
    });           
  }

  ngOnInit(): void {
    this.retrieveAllCustomers();
  }
}

2. Implement list-customers.component.html:

<div *ngIf="customers.length">
    <h3>Customers</h3>
    <br>
    <table class="table table-hover table-sm">
        <thead class="thead-dark">
          <tr>
            <th>Id</th>
            <th>Firstname</th>
            <th>Address</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
            <tr *ngFor="let customer of customers">
              <td>
                <button type="button" style="font-size:10px" class="btn btn-primary" (click)="setCustomerDetails(customer)">
                  {{customer.key}}
                </button>
              </td>
              <td>{{customer.firstname}}</td>
              <td>{{customer.address}}</td>
              <td>
                <button type="button" class="btn btn-danger" 
                  data-toggle="modal" data-target="#delete-modal" 
                                (click)=prepareDeleteCustomer(customer) >&times;</button>
              </td>
            </tr>
        </tbody>
    </table>
</div>

<!-- The Modal -->
<div class="modal fade" id="delete-modal">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
    
    <!-- Modal Header -->
    <div class="modal-header">
      <h4 class="modal-title">Delete!</h4>
      <button type="button" class="close" data-dismiss="modal">&times;</button>
    </div>
    
    <!-- Modal body -->
    <div class="modal-body">
        <div *ngIf="deletedCustomer">
          <p [hidden] = "returnedMessage">
            Do you want delete a customer with id = {{deletedCustomer.key}}
          </p>
          <p [hidden] = "!returnedMessage">
            {{returnedMessage}}
          </p>
        </div>
    </div>
    
    <!-- Modal footer -->
    <div class="modal-footer">
      <button [hidden] = "returnedMessage" type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
      <button [hidden] = "returnedMessage" type="button" class="btn btn-danger" (click)="deleteCustomer()">Delete</button>
      <button [hidden] = "!returnedMessage" type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
    </div>				
    </div>
  </div>
  </div>

<div *ngIf="showCustomer">
    <h3>Update Customer</h3>
    <form (ngSubmit)="updateCustomer()"> 
        <!-- ID -->   
        <div class="form-group">
          <label for="id">Id:</label>
          <input type="numer" class="form-control"
                    id="id" required [(ngModel)]="showCustomer.key" name="id" disabled>
        </div>      
        <!-- First name -->   
        <div class="form-group">
          <label for="firstname">First Name:</label>
          <input type="text" class="form-control" placeholder="Enter Firstname" 
                    id="firstname" required [(ngModel)]="showCustomer.firstname" name="firstname">
        </div>
        <!-- Last name -->
        <div class="form-group">
            <label for="lastname">Last Name:</label>
            <input type="text" class="form-control" placeholder="Enter Lastname" 
                      id="lastname" required [(ngModel)]="showCustomer.lastname" name="lastname">
        </div>  
        <!-- Address -->
        <div class="form-group">
            <label for="address">Address:</label>
            <input type="text" class="form-control" placeholder="Enter Address" 
                      id="address" required [(ngModel)]="showCustomer.address" name="address">
        </div>        
        
        <!-- Age -->
        <div class="form-group">
          <label for="age">Age</label>
          <input type="number" class="form-control" placeholder="Enter Age" 
                      id="age" required [(ngModel)]="showCustomer.age" name="age">
        </div>
     
        <button type="submit" class="btn btn-success">Update</button>
      </form>
</div>
<app-message></app-message>


<script>
  let pathname = window.location.pathname;
  if(pathname == ""){
      $(".nav .nav-item a:first").addClass("active");
      $(".nav .nav-item a:last").removeClass("active");
  } else if (pathname == "/customers") {
      $(".nav .nav-item a:last").addClass("active");
      $(".nav .nav-item a:first").removeClass("active");
  }
  alert("ok");
</script>

Implement Angular Message Component

MessageComponent is used to show all tracing-log messages in html view.

1. Implement message.component.ts:

import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-message',
  templateUrl: './message.component.html'
})
export class MessageComponent {
  constructor(public messageService: MessageService) {}
}

2. Implement message.component.html:

<div *ngIf="messageService.messages.length">
    <h3>Messages</h3>
    <button type="button" class="btn btn-secondary" (click)="messageService.clear()">clear</button>
    <br>
    <ol>
      <li *ngFor='let message of messageService.messages'>
        <div [innerHTML]="message">
        </div>
      </li>
    </ol>
  </div>

Configure Angular 10 Routing Module

To handle the navigation from one view to the next, you use the Angular router. The router enables navigation by interpreting a browser URL as an instruction to change the view.

The following command uses the Angular CLI to generate a basic Angular app with an app routing module, called AppRoutingModule, which is an NgModule where you can configure your routes.

ng new routing-app --routing

How to Define a route? -> There are three fundamental building blocks to creating a route.

1. Import the AppRoutingModule into AppModule and add it to the imports array.
The Angular CLI performs this step for you. However, if you are creating an app manually or working with an existing, non-CLI app, verify that the imports and configuration are correct.


import { AppRoutingModule } from './app-routing.module';
...

@NgModule({
  declarations: [
	...
  ],
  imports: [
	...
    AppRoutingModule,
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. Define your routes in your Routes array for “Angular 10 Nodejs PostgreSQL CRUD Example”:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddCustomerComponent } from './add-customer/add-customer.component';
import { ListCustomersComponent } from './list-customers/list-customers.component';

const routes: Routes = [
  { 
    path: '', 
    component: AddCustomerComponent 
  },
  { 
    path: 'customers', 
    component: ListCustomersComponent 
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

3. Add your routes to your application.
In the index.html file, we add below html code for navigating URL:


<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
  <ul class="navbar-nav">
    <li class="nav-item" id="li_add_customer">
      <a class="nav-link" href="">Add Customer</a>
    </li>
    <li class="nav-item" id="li_list_customers">
      <a class="nav-link" href="/customers">List Customers</a>
    </li>
  </ul>
</nav>

Next, update your component template to include . This element informs Angular to update the application view with the component for the selected route. So in main component,open app.component.ts file, add the tag:


<router-outlet></router-outlet>

Modify Index.html View Page

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularHttpclient</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
  <!-- jQuery library -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <!-- Popper JS -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <!-- Latest compiled JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
</head>
<body>
  <div class="container"  style="font-size:14px">  
    <div class="col-sm-7" style="background: linear-gradient(to bottom, #ffffff 0%, #ffff99 100%); margin:10px;padding:10px; border-radius: 8px">
      <div class="alert" 
            style="background: linear-gradient(to bottom, #99ccff 0%, #ffffff 100%);
                 color:black; border-radius:10px">
          <h3>CRUD Angular Firestore</h3>
          @Copyright by <a href="https://loizenai.com">https://loizenai.com</a> 
          * <span style="color:red">Youtube</span>: <a href="https://www.youtube.com/channel/UChkCKglndLes1hkKBDmwPWA">loizenai</a>
      </div>
      <nav class="navbar navbar-expand-sm bg-primary navbar-dark" style="font-size:16px"; border-radius:8px">
        <ul class="navbar-nav">
          <li class="nav-item" id="li_add_customer">
            <a class="nav-link" href="">Add Customer</a>
          </li>
          <li class="nav-item" id="li_list_customers">
            <a class="nav-link" href="/customers">List Customers</a>
          </li>
        </ul>
      </nav>
      <div>
      <app-root></app-root>
      </div>
    </div>
  </div>
  <script>
    $(document).ready(function() {
      (function(){
        let pathname = window.location.pathname;
        if(pathname == "/"){
            $("#li_add_customer").addClass("active");
            $("#li_list_customers").removeClass("active");
        } else if (pathname == "/customers") {
            $("#li_list_customers").addClass("active");
            $("#li_add_customer").removeClass("active");
        }
      })();
    });
  </script>
</body>
</html>

Integrative Testing Angular 10 CRUD Cloud Firestore

Okay, now we do a set of testcases for the tutorial: “Angular 10 CRUD Cloud Firestore”.

Testcase 1: Angular Post data to Firestore using @angular/fire

Angular 10 Firestore CRUD Example - Angular post data to Firestore
Angular 10 Firestore CRUD Example – Angular post data to Firestore
Angular 10 Firestore CRUD Example - Angular Post all Data to Firestore Successfully
Angular 10 Firestore CRUD Example – Angular Post all Data to Firestore Successfully

Testcase 2: Angular Get all data from Firestore using @angular/fire

Angular Get all data from Firestore - network logs
Angular Get all data from Firestore – network logs
Angular List all data from Firestore on web view
Angular List all data from Firestore on web view

Testcase 3: Angular Put data to Firestore using @angular/fire

Angular 10 Update data to Firestore
Angular 10 Update data to Firestore

Testcase 4: Angular Delete data from Firestore using @angular/fire

Angular Delete data from Firestore successfully
Angular Delete data from Firestore successfully
Check Firestore after doing CRUD operations from Angular 10
Check Firestore after doing CRUD operations from Angular 10

Sourcode

Full Sourcecode for the tutorial “Angular 10 CRUD Firestore – use @angular/fire”:

Angular10-Firestore-CRUD

– Github sourcecode:

Angular-10-CRUD-Cloud-Firestore

Leave a Reply

Your email address will not be published. Required fields are marked *