Angular Firebase CRUD operations using angularFire 7.2.0

In this tutorial, we’ll learn and demonstrate the latest AngularFire 7.2.0, to perform Angular Firebase CRUD operation. The Firebase is one of the most popular and used serverless technology from Google. Allows front-end developers to focus mostly on the frontend instead of on the backend. The Google Firebase offers a wide range of backend services likes hosting, cloud Firestore, Analytics, cloud messaging, cloud storage, and many more.

What we are learning on Angular Firebase ?

In this Angular Firebase tutorial, we will be focusing on Angular Firestore and will perform the following Firebase CRUD operation using the latest angularFire library.

  1. Retrieving a collection records from collection called books.
  2. Adding new record to books collection.
  3. Deleting/editing a document or record.
  4. Editing single field of a document like price of a book on blur event on input.
  5. Peforming firebase query, search by a field
  6. Retrieving a document by id

Firebase CRUD App Screenshot of our Angular book apps.

angular firebase crud
Angular Firebase CRUD example

We can use Firebase Firestore to store data on Google cloud storage. With Firebase we can easily do CRUD operation and Firebase also provides a different option for authentication for Firebase CRUD apps.

Setting up and configure Firebase CRUD apps

Before using Firebase, we need to configure our application. Let first create Firebase angular project.

ng new firebaseCRUDApp
cd firebaseCRUDApp

Setting Firebase project is simple, but it has some steps to be carried out. We’ll divide the configuration section into three parts, otherwise, it will messy and long.

  1. Creating Firebase project and configuring project at Firebase console.
  2. Installing AngularFire and adding Bootstrap UI and icon.
  3. Creating components, service to implementing Firebase activities

Create and configure our project in the Firebase console.

Let open the browser and type https://firebase.google.com, we need to create a project on firebase and configure the Google cloud Firestore database for it.

Angular firebase CRUD

In the Firebase console, we need to click on Add Project to create a new project and we should give the name of our project, In our case let say book as a project name.

Angular firebase CRUD example

Once we add our project name, let click on the continue button, it will take us to these options. For this example we don’t need Google Analytics, let disable it.

Angular firestore operation

Clicking on the Create project will create a Firebase project for us.

Create Firebase web project

Now we need Firebase configuration for our web application. Our front-end application needs the web configuration to connect to the Firebase project at Google Firestore.

In the Firebase project dashboard, we have many options, and let click on the “Web” icon as shown in the image below.

Firebase web config

Once, we click on the web icon, we have to provide a nickname for our app. You can use any name of your choice. Here we will use the name bookWebApp, the same name as ours. Click on the “Register App” button.

Angular firestore example

Add Firebase web config value in Front-end project

We need to copy this our firebase project API key, and past it in our client project src/environments/environment.ts as shown in the code snippet below. The below code is just for demo, you can replace it with your own API code.

export const environment = {
  production: false,
  firebase: {
    apiKey: "AIzffdfdf--jSe9ys",
    authDomain: "book-sss.firebaseapp.com",
    projectId: "book-sss4db",
    storageBucket: "book-8db.appspot.com",
    messagingSenderId: "98759698508",
    appId: "1:959685345:web:30a3c6bf6d8fca5837b6cc"
  }
};
Note : The above configuration is dummy, you have to replace your Firebase config value, which you get from Firebase project.

Create cloud firestore databse

We have almost finished our firebase project configure in firebase.com, now we need to create our firebase database. Let’s click on the Firestore database icon as shown below.

Create Firebase project

Click on create database will ask us for production or test mode and this is an example. Let select test mode, now our database is ready. In later articles, we will learn how to perform Firebase operations using AngularFire.

Installing AngularFire and Adding Bootstrap library

We had successfully set up the Firebase project at the Firebase cloud console. Let now add Bootstrap and bootstrap icon libraries to our project.

ng add @ng-bootstrap/ng-bootstrap
npm install bootstrap-icons --save

To use bootstrap icons we need to import, Bootstrap-icon style in style.scss or style.css file.

/* Importing Bootstrap SCSS file. */
@import '~bootstrap/scss/bootstrap';
@import '~bootstrap-icons/font/bootstrap-icons';

Install AngularFire library to our project

We need to install the angularFire library to perform the Firebase CRUD operation in our Angular application. The angularFire is the Angular library for Firebase, the latest AngularFire 7 has lots of new changes, we can easily perform Firebase CRUD operation using it.

Let run the command below to add the Firebase project to our Angular project

ng add @angular/fire

While running the above command will take a few minutes, asking you to select some options as shown in the image below.

AngularFire add command
AngularFire Command
  1. First we have to select what feature we want to add in our project, for us we have to select Firestore.
  2. On select Firestore, will ask you to login to Firebase and if you are already connect then it will take automatically login.
  3. At last we have to select project name, in our case Firebase console project is books, select it.

Once we successfully add the AngularFire library, we need to set the Firebase configuration in the app.module.ts file to connect to the Firebase project in the Google Firebase cloud.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { getFirestore, provideFirestore } from '@angular/fire/firestore';

import { environment } from 'src/environments/environment';
import { FormsModule } from '@angular/forms';


@NgModule({
  declarations: [
    AppComponent,
    BooksComponent,
    BookComponent,
    HomeComponent,
    EditBookComponent,
    SearchComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    NgbModule,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => getFirestore()),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We also need Forms, so we had added FormsModule to use the Angular template form for adding and editing a book record. The Firebase configuration setting is different from the previous version of AngularFire, where we use AngularFireModule, this is not the case in the latest version.

We have to use the provideFirebaseApp and provideFireStore function to connect to our Firebase project.

Creating all components, book service for Firebase CRUD

To implement the firebase CRUD operation, we will need a form that allows us to add/edit book records. All book record activities like adding a new book, deleting, updating, and listing are done in our book service, which is consumed by components. Let add all components needed for Firebase CRUD operation.

ng generate component components/home
ng generate component components/book
ng generate component components/books
ng generate component components/search

In our home component contains two parts.

  1. Book component for adding new book records
  2. Books component, list of books already added.

We also need the book service, and modal called edit-book modal to implement editing of a record.

ng generate component modal/editBook
ng generate service services/book

We also need a model for the book, so that we can implement a strict type, to minimize error. Let create folder models in src/app and add a file called book.model.ts file.

export interface IBook {
    id?: string;
    name : string;
    author : string;
    genre : string;
    price : number;
}

Configure routing of Firestore application, we have two navigation buttons, home and search component. In the app.routing.module.ts, add routing configuration for both.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { SearchComponent } from './components/search/search.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'search', component: SearchComponent }
];

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

The home component has two child components, one for adding new records and the other for listing all records. Let’s edit the home.component.html file

<div class="container">
    <div class="row">
        <div class="col-md-4">
            <app-book></app-book>
        </div>
        <div class="col-md-7">
            <app-books></app-books>
        </div>
    </div>
</div>

In the app.component.html template, let add the navigation part.

<div class="jumbotron">
  <h2 style="text-align:center;">
    Book Collection
  </h2>
  <button type="button" routerLink="" class="btn btn-link">
    Home
   </button>
  <button type="button" routerLink="search" class="btn btn-link">
     Search
  </button>
</div>

<router-outlet></router-outlet>

Angular Firestore CRUD operation

Let implement Angular Firestore CRUD operation, as we had completed all configuration and setting up of the Firebase project. The Firestore CRUD stands for (Create, read, update and delete).

Firebase Create a record

We’ll be implementing one by one CRUD operation, let first perform creating a new record in Firebase. In our services/book.service.ts edit code to implement create operation.

import { Injectable } from '@angular/core';
import {
  Firestore, addDoc, collection, collectionData,
  doc, docData, deleteDoc, updateDoc, DocumentReference, setDoc
} from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { IBook } from '../models/book.model';

@Injectable({
  providedIn: 'root'
})
export class BookService {

  constructor(private firestore: Firestore) { }

  addBook(book: IBook) {
    const booksRef = collection(this.firestore, 'books'); 
    return addDoc(booksRef, book);
  }
}

We need to import Firestore from ‘@angular/fire/firestore’ and also need to declare it in the constructor. We also import many objects and classes from @angular/fire/firestore, we need all this later.

First, we need a reference to our collection books, which we can get from collection by passing two-argument the Firestore and the name of the collection in our case books. Now we use addDoc to add create a new record book using the reference of a collection as shown above.

Create form for adding new book record

We need a form, to add a new book record, here is a screenshot for adding a record in Firestore.

Angular firestore create operation

In the book.component.ts file, we need to import BookService and inject it into the book constructor. Let edit the book component to consume the BookService to add a new record.

import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';

@Component({
  selector: 'app-book',
  templateUrl: './book.component.html',
  styleUrls: ['./book.component.scss']
})
export class BookComponent implements OnInit {

  book: IBook = { name: '', author: '', genre: '', price: 0 };

  constructor(private bookService: BookService) { }

  ngOnInit() {
  }

  onSubmit(form: NgForm) {
    this.bookService.addBook(form.value).
      then(() => form.reset());
  }
}

Let add a template form, to allow users to input a book record.

<div>
  <h4>Add new book record</h4>
  <form #bookForm="ngForm" (ngSubmit)="onSubmit(bookForm)">
    <div class="form-group">
       <label>Book Name</label>
       <input class="form-control" name="name" #name="ngModel" 
        [(ngModel)]="book.name" placeholder="Book Name" required>
    </div>

    <div class="form-group">
      <label>Author</label>
      <input class="form-control" name="author" #name="ngModel" 
        [(ngModel)]="book.author" placeholder="Author" required>
    </div>

     <div class="form-group">
       <label>Genre</label>
       <select class="form-control" name="genre" #name=ngModel 
         [(ngModel)]="book.genre">
          <option value="Novel">Novel</option>
          <option value="Non Fiction">Non Fiction</option>
          <option value="Biography">Biography</option>
       </select>
      </div>

      <div class="form-group">
        <label>Price</label>
        <div class="input-group">
           <div class="input-group-addon">
               <i class="bi bi-currency-dollar"></i>
           </div>
           <input class="form-control" name="price" #name="ngModel" 
             [(ngModel)]="book.price" placeholder="Price" required>
            </div>
        </div>

        <div class="form-group float-right">
           <button type="submit" class="btn btn-success" 
             [disabled]="!bookForm.valid" [disabled]="bookForm.invalid">
              <i class="bi bi-plus"></i>Add Book</button>
        </div>
    </form>
</div>

Clicking on submit button will add a record to Firestore, It is best to keep API access outside of the component. We use service to access API calls to Firebase, service acts as state management allows us to share service code among different components.

Retrieve Firestore data collection

In the books component, we are displaying all book records of collection books. Let first edit the book.service.ts file to retrieve all documents from a collection.

getBooks(): Observable<IBook[]> {
   const booksRef = collection(this.firestore, 'books');
   return collectionData(booksRef, { idField: 'id' }) as Observable<IBook[]>;
 }

We use collectionData to get all records from collections, to get documents with the id we need to add { idField: ‘id’ }. In the previous version of AngularFire is a little bit of extra work, now getting documents with id is easy. The getBooks() return observable of type IBook array, we are consuming this observable in books component.

Angular firestore get a collection

Now in the books.component.ts file, we need to import and inject BookService to consume the getBooks() method from BookService and let edit this component.

import { Component, OnInit } from '@angular/core';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { EditBookComponent } from '../modal/edit-book/edit-book.component';

@Component({
  selector: 'app-books',
  templateUrl: './books.component.html',
  styleUrls: ['./books.component.scss']
})
export class BooksComponent implements OnInit {
  books: IBook[] = [];

  constructor(
    private bookService: BookService,
    private modal: NgbModal) { }

  ngOnInit() {
    this.bookService.getBooks().subscribe((res: IBook[]) => {
      this.books = res;
    })
  }

  editModal(book: IBook) {
    const modalRef = this.modal.open(EditBookComponent, {
      size: 'lg',
      centered: true,
      windowClass: 'dark-modal',
    });

    modalRef.componentInstance.id = book.id;
  }

  deleteBook(book: IBook) {
    if (confirm('Are you sure to delete this record ?') == true) {
      this.bookService.deleteBook(book).then(() => 
       console.log('delete successful'));
    }
  }
}

In this component typescript, we also have code to edit and delete records. For time being let only focus on ngOnit to get books record. Now in the book.component.html template, let add a table to display the book’s records.

<table class="table table-striped">
  <thead>
   <tr>
     <th scope="col">#</th>
     <th scope="col">Name</th>
     <th scope="col">Author</th>
     <th scope="col">Genres</th>
     <th scope="col">Price</th>
     <th scope="col">Edit</th>
     <th scope="col">Delete</th>
   </tr>
  </thead>
  <tbody *ngIf="books">
    <tr *ngFor="let book of books; index as i">
      <th scope="row">{{ i+1 }}</th>
      <td>{{ book.name }}</td>
      <td>{{ book.author }}</td>
      <td>{{ book.genre }}</td>
      <td>{{ book.price }}</td>
      <td>
        <i class="bi bi-pencil-square" style="color: green;" 
           (click)="editModal(book)"></i>
      </td>
      <td>
        <i class="bi bi-trash" (click)="deleteBook(book)" style="color: red;"></i>
      </td>
    </tr>
   </tbody>
</table>

Firestore CRUD delete operation

In the books component, we have a list of all books from the collection books. We also add pencil icons to edit and delete icons to delete on each book on the list. Clicking on the delete icon will invoke delete a record on the collection list. But first, we need to add the corresponding delete function in the book.service.ts file, let add it.

deleteBook(book: IBook) {
    const bookDocRef = doc(this.firestore, `books/${book.id}`);
    return deleteDoc(bookDocRef);
}

The consumer of this deleteBook() method is already added in the previous section books component. We only have to pass the id of the book record to delete.

Firebase CRUD update and set operation

We have completed CRUD operations like create, delete and read. But now we are left with update and set operation of a record. Let do this in our edit-book modal component, as shown in the image below.

Angular Firebase CRUD operation update

Before implementing the edit book modal, we need to add it corresponding update and set method in the book.service.ts file. Let add set, update and retrieve the Firebase document by id operations in the book.service.ts file.

getBookByID(id: string) {
  const bookRef = doc(this.firestore, `books/${id}`);
  return docData(bookRef, { idField: 'id' }) as Observable<IBook>;
}

updateBook(book: IBook) {
  const bookDocRef = doc(this.firestore, `books/${book.id}`);
  return setDoc(bookDocRef, book);
}

modifyBookPrice(book: IBook, amount: number) {
  const bookDocRef = doc(this.firestore, `books/${book.id}`);
  return updateDoc(bookDocRef, { price: amount });
}
setDocupdateDoc
Destructively updates a document’s data, if the document didn’t exist it will create a new document.Non-destructively updates a document’s data. Edit field or property of the document.

In the books component, we have an edit icon, and clicking on it will invoke editModal(book: IBook) which in turn opens modal for edit book with an id of that book.

Now in the edit book modal, we are performing the following activities.

  • On blur on price input will set new price value for book record.
  • On clicking on Update Book will update book to new value which we have enter in form.

Let edit the edit-book.component.ts file, we also need to retrieve a book record by using it id

import { Component, Input, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';

@Component({
  selector: 'app-edit-book',
  templateUrl: './edit-book.component.html',
  styleUrls: ['./edit-book.component.scss']
})
export class EditBookComponent implements OnInit {
  @Input() id: string;
  book: IBook;

  constructor(
    private bookService: BookService,
    public activeModal: NgbActiveModal)
     { }

  ngOnInit() {
    if (this.id)
      this.bookService.getBookByID(this.id).subscribe(res => {
        this.book = res
      });
  }

  onUpdate() {
    this.bookService.updateBook(this.book).then(() => {
      this.activeModal.close();
      console.log('Data add successfully');
    })
  }

  setPrice(book: IBook, price: number) {
    this.bookService.modifyBookPrice(book, price)
  }
}

We need to inject BookService in the edit-book component, now let edit the edit-book component template to add a form for edit and set.

<div *ngIf="book" class="container">
  <h4>Edit book record</h4>
  <form #bookForm="ngForm" (ngSubmit)="onUpdate()">
    <div class="form-group">
      <label>Book Name</label>
      <input class="form-control" name="name" #nameCtrl="ngModel" 
        [(ngModel)]="book.name" placeholder="Book Name" required>
    </div>

    <div class="form-group">
      <label>Author</label>
      <input class="form-control" name="author" #authorCtrl="ngModel" 
        [(ngModel)]="book.author" placeholder="Author" required>
    </div>

    <div class="form-group">
      <label>Genre</label>
      <select class="form-control" name="genre" #genreCtrl=ngModel 
        [(ngModel)]="book.genre">
        <option value="Novel">Novel</option>
        <option value="Non Fiction">Non Fiction</option>
        <option value="Biography">Biography</option>
      </select>
    </div>

    <div class="form-group">
      <label>Price</label>
      <div class="input-group">
        <div class="input-group-addon">
           <i class="bi bi-currency-dollar"></i>
        </div>
        <input class="form-control" name="price" #priceCtrl="ngModel" 
           (blur)="setPrice(book, priceCtrl.value)"
           [(ngModel)]="book.price" placeholder="Price" required>
       </div>
    </div>

    <div class="form-group float-right">
     <button type="submit" class="btn btn-success" [disabled]="!bookForm.valid">
        <i class="bi bi-plus"></i>Update Book</button>
     </div>
  </form>
</div>

Conclusion

Now we had completed the Angular Firestore CRUD operation, as this tutorial become lengthy, we will cover Angular Firestore query and search operation in separate articles. I hope you got some idea, how to use AngularFire latest.

Related Post

Spread the love

2 thoughts on “Angular Firebase CRUD operations using angularFire 7.2.0”

Leave a Comment

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

Scroll to Top