Tutorial: Angular 9 CRUD Firebase Realtime Database – use @angular/fire Example
The Firebase Realtime Database is a cloud-hosted NoSQL database that lets you store and sync data between your users in realtime. In the tutorial, I introduce how to build an “Angular 9 CRUD Firebase Realtime Database Example ” project with the help of @angular/fire
lib to do CRUD operation: POST/GET/PUT/DELETE requests with step by step coding examples.
– I draw a fullstack overview diagram architecture from Angular frontend to Firebase Realtime Database.
– I illustrate details about @angular/fire
CRUD operations.
– I implement Angular CRUD application with the @angular/fire lib to do CRUD request (Post/Get/Put/Delete) to Firebase Realtime database.
- Overvier Architecture Diagram – Angular 9 CRUD Firebase Realtime Database use @angular/fire
- Firebase Realtime Database CRUD Operation with @angular/fire
- Implement Angular 9 CRUD Firebase Realtime Database using @angular/fire
- Angular 9 CRUD Application Overview with Firebase Realtime Database
- Create Angular 9 Application
- Add Firebase configuration to Angular environments variable
- Setup Angular @NgModule with @angular/fire
- Create Angular Typescript Model
- Implement Angular 9 CRUD Firebase Service
- Implement Angular post/get/put/delete components
- Configure Angular 9 Routing Module
- Modify Index.html View Page
- Testing
- Sourcode
Overvier Architecture Diagram – Angular 9 CRUD Firebase Realtime Database use @angular/fire
Overall Architecture System: Angular + Firebase Realtime Database

We use @angular/fire
to integrate Angular Application with Firebase. Angular will use a service to do CRUD operations with Firebase Realtime Database and show data on user-view through components.
Angular 9 CRUD Firebase Application Design

– Angular 9 CRUD Application is designed with 3 main layers:
- Service Layer is used to do CRUD requests with Firebase Realtime Database
- Component Layer is used to define Angular Components to display views in Browser.
- Router Layer is used to define all Angular navigation URLs mapping with the corresponding Angular Components

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 Firebase Realtime Databaselist-customer
component is used to display all data on views, delete a data and update a data with
a given key to Firebase Realtime Database using @angular/firemessage
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 Firebase Realtime Databasemessage.service.ts
defines an array storage to log all messages when the Angular 9 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.
Firebase Realtime Database CRUD Operation 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 9 + Firebase RealTime Database using @angular/fire

Firebase Object CRUD operations
To do CRUD operations with Firebase Object, we use a set methods of interface AngularFireObject
as below:
export interface AngularFireObject {
query: DatabaseQuery;
valueChanges(): Observable;
snapshotChanges(): Observable>;
update(data: Partial): Promise;
set(data: T): Promise;
remove(): Promise;
}
– Firebase Create an Object binding/retrieve operation
item: AngularFirestoreDocument;
// db: AngularFirestore
this.item = db.doc('item');
// or
Observable item = db.doc('item').valueChanges();
– Firebase Create Object operation
// db: AngularFirestore
const itemRef = db.doc('item');
// set() for destructive updates
itemRef.set({ name: 'loizenjava'});
– Firebase Update Object operation
// db: AngularFirestore
const itemRef = db.doc('item');
itemRef.update({ url: 'https://loizenjava.com'});
– Firebase Delete Object operation
// db: AngularFirestore
const itemRef = db.doc('item');
itemRef.delete();
Firebase List of Objects CRUD operations
– Firebase Create a List Binding/ Retrieve operation:
* 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;
// 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;
// db: AngularFirestore
this.items = db.collection('items').snapshotChanges();
– Firebase Add Object operation to a List
// db: AngularFirestore
const itemsRef = db.collection('items');
itemsRef.add({ site: 'loizenjava.com' });
– Firebase 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: 'gkz.com' });
// update(): non-destructive update
// only updates the values specified
const itemsRef = db.collection('items'); // db: AngularFirestore
itemsRef.doc(key).update({ url: 'loizenjava.com' });
– Firebase 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 9 CRUD Firebase Realtime Database using @angular/fire
Angular 9 CRUD Application Overview with Firebase Realtime Database

– For more details, we go back to the session: Angular CRUD Design
Create Angular 9 Application
We create Angular 9 CRUD project by commandline: ng new AngularFirebaseCrudDatabase
.
– 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: "loizenjava-firebase.firebaseapp.com",
databaseURL: "https://loizenjava-firebase.firebaseio.com",
projectId: "loizenjava-firebase",
storageBucket: "loizenjava-firebase.appspot.com",
messagingSenderId: "887328809823"
}
};

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 { AngularFireDatabaseModule } from '@angular/fire/database';
import { environment } from '../environments/environment';
import { AppComponent } from './app.component';
...
@NgModule({
declarations: [
AppComponent
...
],
imports: [
BrowserModule,
FormsModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireDatabaseModule, // for database
...
],
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 9 CRUD Firebase Service
For interacting with Firebase Realtime Database, we use @angular/fire AngularFireDatabase
to implement a firebase crud (post/get/put/delete) service:
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from '@angular/fire/database';
import { Customer } from './customer';
@Injectable({
providedIn: 'root'
})
export class CustomerService {
private dbPath = '/customers';
customersRef: AngularFireList<Customer> = null;
constructor(private db: AngularFireDatabase) {
this.customersRef = db.list(this.dbPath);
}
...
}
Angular Firebase Post request
createCustomer(customer: Customer): void {
this.customersRef.push(customer);
}
We use a method push(data: T): database.ThenableReference;
to post a data to Firebase realtime database.
Angular Firebase Get request
getCustomersList(): AngularFireList<Customer> {
return this.customersRef;
}
Angular Firebase Put request
updateCustomer(key: string, value: any): Promise<void> {
return this.customersRef.update(key, value);
}
Angular HttpClient Delete request
deleteCustomer(key: string): Promise<void> {
return this.customersRef.remove(key);
}
Implement Angular post/get/put/delete components
Implement Angular Post Component: adding data
AddCustomerComponent
is used to post a new data Customer to Firebase.
– 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) >×</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">×</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 9 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 9 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 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 Firebase Realtime Database</h3>
@Copyright by <a href="https://loizenjava.com">https://loizenjava.com</a>
* <span style="color:red">Youtube</span>: <a href="https://www.youtube.com/channel/UChkCKglndLes1hkKBDmwPWA">loizenjava</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 + Firebase Realtime Database
Okay, now we do a set of testcases for the tutorial: “Angular 9 CRUD Firebase Realtime Database”.
Testcase 1: Angular Post data to Firebase Realtime database using @angular/fire


Testcase 2: Angular Get all data from Firebase Realtime database using @angular/fire


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

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


Sourcode
Full Sourcecode for the tutorial “Angular 9 CRUD Firebase Realtime Database – use @angular/fire”:
Angular-9-Firebase-Crud-Database
– Github sourcecode: