Angular CRUD operation on Firebase

We can use Firebase to store data. With Firebase we can easily do CRUD and it provides login with the different option. We are creating an Angular book app with firebase through package angularfire2.  We will be doing following as

  1. We insert/deleting/editing a book record and display all the book on our page.
  2. We are using CDN of Bootstrap 4 and font awesome in index.html of src file.

App Screenshot of our an Angular book apps

Step 1: Adding the following CDN font-awesome and bootstrap

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

 

Step 2:  Setup the project and Installing the required Plugin

We have to install angularfire2 package to use the power of RxJS, Angular, and Firebase. to perform realtime CRUD operation on Firebase server.

npm install firebase angularfire2 --save

Here we are creating the main component called books-component containing (book-component and book-list-component) and share folder containing model and service. File structure of our Angular book apps

Here we will be creating our book component and services as follow

ng g c books

We will creating child component in cd src/app/books/
ng g c book
ng g c book-list

create shared folder in book component containing book model and service
ng g class book.model
ng g s book

Add the following code for book model in app/books/shared/book.model.ts

export class Book{
    $key : string;
    bookname : string;
    author : string;
    genre : string;
    price : number;
}

Add the following code for book service in app/shared/book.service.ts

import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { Book } from './book.model';

@Injectable()
export class BookService {

  bookList: AngularFireList<any>;
  selectedBook : Book = new Book();
  
  constructor(private firebase: AngularFireDatabase) {}

  getData(){
    this.bookList = this.firebase.list('books');
    return this.bookList;
  }

  insertBook(book : Book){
    this.bookList.push({
      bookname : book.bookname,
      author : book.author,
      genre : book.genre,
      price : book.price,
    })
  }

  updateBook(book : Book){
    this.bookList.update(book.$key, {
      bookname : book.bookname,
      author : book.author,
      genre : book.genre,
      price : book.price,
    })
  }

  deleteBook(key : string ){
    this.bookList.remove(key);
  }

}

 

In app/books component we have to import to book service provider. Add the following code in app/books.component.html file, here we are adding both the child component tag, one component to display the book form and other component to display the list of all book from firebase database.

<div  class="jumbotron">
  <h2 style="text-align:center;">
    Book Collection
  </h2>
</div>
<div class="container">
  <div class="row">
    <div class="col-md-7">
      <app-book></app-book> 
    </div>
    <div class="col-md-5">
      <app-book-list></app-book-list>
    </div>
  </div>
</div>

Add the following code in app/books.component.ts file

import { Component, OnInit } from '@angular/core';
import { BookService } from './shared/book.service';

@Component({
  selector: 'app-books',
  templateUrl: './books.component.html',
  styleUrls: ['./books.component.css'],
  providers: [ BookService]
})
export class BooksComponent implements OnInit {

  constructor(private bookService : BookService) { }

  ngOnInit() {
  }

}



Step 3: Adding code to child component

In books component we have two child component, first we will add code to child book-component to display the form. Add the following code in app/books/book/book-component.ts file

<form #bookForm="ngForm" (ngSubmit)="onSubmit(bookForm)">
  <input type="hidden" name="$key" #$key="ngModel" [(ngModel)]="bookService.selectedBook.$key">
  <div class="form-group">
    <label>Book Name</label>
    <input class="form-control" name="bookname" #name="ngModel" [(ngModel)]="bookService.selectedBook.bookname" placeholder="Book Name" required>
  </div>

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

  <div class="form-group">
    <label>Genre</label>
    <select class="form-control" name="genre" #name=ngModel [(ngModel)]="bookService.selectedBook.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="fa fa-inr"></i>
      </div>
      <input class="form-control" name="price" #name="ngModel" [(ngModel)]="bookService.selectedBook.price" placeholder="Price" required>
    </div>
  </div>

  <div class="form-group">
    <button type="submit" class="btn btn-default" [disabled]="!bookForm.valid" >
      <i class="fa fa-floppy-o" aria-hidden="true"></i> Submit</button>
    <button type="button" class="btn btn-default" *ngIf="bookService.selectedBook.$key != null" 
      (click)="onDelete(bookForm)">
      <i class="fa fa-trash"></i> Delete</button>
    <button type="button" class="btn btn-default" (click)="resetForm()">
      <i class="fa fa-repeat"></i> Reset</button>
  </div>
</form>

Add the following code in app/books/book/book-component.ts file

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';

import { BookService} from '../shared/book.service';

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

  constructor(private bookService : BookService) { }

  ngOnInit() {
    this.resetForm();
  }

  onSubmit(form : NgForm){
    if(form.value.$key == null)
      this.bookService.insertBook(form.value);
    else
      this.bookService.updateBook(form.value);
    this.resetForm(form);
  }

  resetForm(form? : NgForm){
    if(form != null)
      form.reset();

    this.bookService.selectedBook = {
      $key : null,
      bookname : '',
      author : '',
      genre : '',
      price : 0,
    }
  }
  onDelete(form : NgForm ){
    if(confirm('Are you sure to delete this record ?') == true) {
      this.bookService.deleteBook(form.value.$key);
      this.resetForm(form);
    }
  }

}

In onSubmit() we have if condition to determine whether we are inserting new record or editing existing data. If a value of the variable $key is null this means we are inserting new record otherwise we are calling updateBook methods of service to edit the existing record.

In book-list component, in this child component, we are displaying the book detail information on the page. In app/books/book-list/book-list.component.html add the following code.

<ul class="list-group hover">
  <h4>Book Name - Author - Genres</h4>
  <li class="list-group-item" *ngFor="let book of bookList" (click)="onItemClick(book)">
    {{book.bookname}} - {{book.author}}  : {{book.genre}}
  </li>
</ul>

In app/books/book-list/book-list.component.ts add the following code.

import { Component, OnInit } from '@angular/core';
import { AngularFireList } from 'angularfire2/database';

import { BookService } from '../shared/book.service';
import { Book } from '../shared/book.model';

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

  bookList: Book[];
  
  constructor(private bookService : BookService) { }

  ngOnInit() {
    var x = this.bookService.getData();
    x.snapshotChanges().subscribe(item => {
      this.bookList = [];
      item.forEach(element => {
        var y = element.payload.toJSON();
        y["$key"] = element.key;
        this.bookList.push(y as Book);
      })
    })
  }

  onItemClick(book : Book){
    this.bookService.selectedBook = Object.assign({}, book);
  }

}

Note :  We have onItemClick(book : Book){ this.bookService.selectedBook=Object.assign({}, book); } selected red line of book-list.component.ts code should be same as code of form element of book.component.hmtl as <inputclass=”form-control”name=”bookname” #name=”ngModel” [(ngModel)]=”bookService.selectedBook.bookname” placeholder=”Book Name”required> When we click on one of book-list on page will automatically add to the form element, so that we can easily modifed the exiting book record.

Step 4:  We have to add following code in firebase setup code in environments/environment.ts  

export const environment = {
  production: false,

  firebaseConfig : {
    apiKey: "AIzaSyA1KzVfeo9yE6OyQiNrBx2MBvMVxVngctI",
    authDomain: "bookangular-d47f9.firebaseapp.com",
    databaseURL: "https://bookangular-d47f9.firebaseio.com",
    projectId: "bookangular-d47f9",
    storageBucket: "bookangular-d47f9.appspot.com",
    messagingSenderId: "572743007724"
  }
};

At last, we have to register the provider for angularfire2 plugin, form module and we also have to add reference of all component in app/app.module.ts file.

import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { BooksComponent } from './books/books.component';
import { BookComponent } from './books/book/book.component';
import { BookListComponent } from './books/book-list/book-list.component';
import { environment} from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent,
    BooksComponent,
    BookComponent,
    BookListComponent
  ],
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireDatabaseModule,
    FormsModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

Add the CSS code for book apps in style.css in src folder, here we are adding hand cursor on the book list and button.

/* You can add global styles to this file, and also import other style files */
input.ng-invalid.ng-dirty{
    border: 1px solid red;
}


button, ul.list-group.hover li.hover{
    cursor: pointer;
}