Introduction

In this article, we are going to learn how to do CRUD operations in Angular applications with Firebase 'RealTime Database' and ' Cloud Firestore'.

What is CRUD ?

CRUD is an acronym for CREATE, READ, UPDATE, DELETE.

What is Firebase ?

Firebase is a technology that allows us to create web applications without server-side-programming, making development faster and easier. It can control data without thinking about how data is stored and synchronized across different instances of the application in real-time.
It is a mobile platform from Google offering a number of different features.These features allow users to save and retrieve data to be accessed from any device or browser.
Prerequisites
  • Basic knowledge of Angular
  • Visual Studio Code must be installed
  • Angular CLI must be installed
  • Node JS must be installed
  • Basic Knowledge of Firebase
Step 1
Let's create a new Angular project using the following NPM command.
Open cmd and and type the following command.
  1. ng new angularCRUD-using-firebase
Step 2
In cmd go to the project folder and type 'code .' to open the project in Visual Studio code .
Step 3
Now, let's create a new component by using the following command and nstall Firebase and Angular Firebase.
  1. npm install firebase @angular/fire
Step 4
To integrate our Angular application with Firebase just visit my article Introduction to Firebase. There I explained in detail how to create an account in Firebase and how to setup the project .
Go to Firebase and login in console.firebase.com
On the left menu of the home page Click on Project overview. Go to Settings. On the general tab, scroll down and you can see your configuration.You only need to copy the config object from this page.
Step 5
Copy the configuration and paste it inside your enviroment.ts file
Step 6
Go to environment.ts file and paste your firebase configuration code inside firebase:{} (You need to create one object)
Step 7
Open the file app.module.ts and paste the below code,
  1. import { BrowserModule } from '@angular/platform-browser';
  2. import { NgModule } from '@angular/core';
  3. import { AppComponent } from './app.component';
  4. import { FormsModule } from '@angular/forms';
  5. import { HttpClientModule } from '@angular/common/http';
  6. import { AngularFireModule } from '@angular/fire';
  7. import { AngularFireDatabaseModule } from '@angular/fire/database';
  8. import { AngularFirestoreModule } from '@angular/fire/firestore';
  9. import { environment } from 'src/environments/environment';
  10. import { RealTimeDatabaseComponent } from './real-time-database/real-time-database.component';
  11. import { CloudFirestoreComponent } from './cloud-firestore/cloud-firestore.component';
  12. @NgModule({
  13. declarations: [
  14. AppComponent,
  15. RealTimeDatabaseComponent,
  16. CloudFirestoreComponent
  17. ],
  18. imports: [
  19. BrowserModule,
  20. FormsModule,
  21. HttpClientModule,
  22. AngularFireModule.initializeApp(environment.firebase),
  23. AngularFireDatabaseModule,
  24. AngularFirestoreModule
  25. ],
  26. providers: [AngularFireModule],
  27. bootstrap: [AppComponent]
  28. })
  29. export class AppModule { }
The above image shows that we need to import Angular fire module and inside initializeapp and give the path of our firebase web configuration. Also we have imported 2 files ,Angular Fire database module for Realtime Database and Angular FireStore module for Cloud Firestore.
Step 8
There are two ways to store our data in firebase
  1. Cloud Firestore- Store and sync data in real time across all connected clients
  2. Real-Time Database- Realtime Updates poweful queries and automatic scaling
In this article we are storing data in both ways to store data in Cloud Firestore and in Real-time Database.
Using Cloud Firestore
Step 9
Create a component "cloud -firestore" using the following command
  1. ng g c cloud-firestore
Step 10
Now, open the cloud-firestore.component.ts file and add the following code in this file,
  1. import { Component, OnInit } from '@angular/core';
  2. import { Country } from '../country';
  3. import { CountryService } from '../country.service';
  4. import { AngularFirestore } from '@angular/fire/firestore';
  5. @Component({
  6. selector: 'app-cloud-firestore',
  7. templateUrl: './cloud-firestore.component.html',
  8. styleUrls: ['./cloud-firestore.component.css']
  9. })
  10. export class CloudFirestoreComponent {
  11. updateCountry: boolean = false;
  12. countries: Country[];
  13. Country: Country = new Country();
  14. countryId = null;
  15. isToggle: boolean = false;
  16. formSubmitted: boolean;
  17. isDelete: boolean;
  18. constructor(private _countryService: CountryService,
  19. private angularFirestore: AngularFirestore
  20. ) {
  21. this.getAllCountry();
  22. }
  23. getAllCountry() {
  24. this._countryService.getAllCountry().subscribe((data: any) => {
  25. this.countries = data.map(e => {
  26. return {
  27. id: e.payload.doc.id,
  28. ...e.payload.doc.data()
  29. } as Country;
  30. });
  31. console.log(this.countries);
  32. });
  33. }
  34. onSubmit(f) {
  35. if (f.form.valid) {
  36. const CountryData = JSON.parse(JSON.stringify(this.Country));
  37. debugger;
  38. if (this.countryId == null) {
  39. this._countryService.addCountryInforamtion(CountryData);
  40. } else {
  41. this._countryService.updateCountryInforamtion(this.countryId, CountryData);
  42. }
  43. this.Country = new Country();
  44. f.submitted = false;
  45. this.formSubmitted = true;
  46. this.updateCountry = false;
  47. setInterval(() => {
  48. this.formSubmitted = false;
  49. }, 2000);
  50. }
  51. }
  52. //Edit Country method
  53. editCountry(countryId) {
  54. this.countryId = countryId;
  55. let obj: any = this.countries.filter((x: any) => {
  56. return x.id == countryId;
  57. });
  58. this.updateCountry = true;
  59. this.Country = obj[0];
  60. }
  61. // Delete Country method
  62. deleteCountry(countryId) {
  63. if (confirm('Please note! This action can NOT be undone. Are you sure you want to delete?')) {
  64. this._countryService.deleteCountry(countryId);
  65. this.isDelete = true;
  66. setInterval(() => {
  67. this.isDelete = false;
  68. }, 2000);
  69. }
  70. }
  71. }
Step 11
Open the cloud-firestore.component.html file and add the following code in this file,
  1. <div class="card">
  2. <form name="form" (ngSubmit)=" onSubmit(f)" #f="ngForm" novalidate>
  3. <div class="card-body pb-0">
  4. <div class="card">
  5. <div class="card-header main-search dash-search">
  6. <h1 style="text-align: center;">
  7. MANAGE COUNTRY- Using Cloud Firestore
  8. </h1>
  9. </div>
  10. </div>
  11. <div class="row">
  12. <div class="col-12 col-md-12">
  13. <div class="card">
  14. <div *ngIf="!updateCountry" class="card-header">
  15. Add New Country
  16. <h3 *ngIf="formSubmitted" style="text-align: center; color: green;">New Country has been
  17. added
  18. successfully...</h3>
  19. <h3 *ngIf="isDelete" style="text-align: center; color: green;">Country has been deleted
  20. successfully...</h3>
  21. </div>
  22. <div *ngIf="updateCountry" class="card-header">
  23. Update Country
  24. <h3 *ngIf="formSubmitted" style="text-align: center; color: green;">Existing Country has
  25. been updated
  26. successfully...</h3>
  27. </div>
  28. <div class="card-body">
  29. <div class="center-form">
  30. <div class="row">
  31. <div class="col-12 col-md-6">
  32. <div class="form-group">
  33. <label class="col-form-label">Name<span
  34. class="mandatoryFieldColor">*</span></label>
  35. <input type="text" class="form-control" name="CountryName" autofocus
  36. [(ngModel)]="Country.CountryName" #country="ngModel"
  37. [ngClass]="{ 'is-invalid': f.submitted && country.invalid }" required />
  38. <div *ngIf="f.submitted && country.invalid" class="invalid-feedback">
  39. <div *ngIf="country.errors.required || country.pristine==false">Country
  40. Name is required</div>
  41. </div>
  42. </div>
  43. </div>
  44. <div class="col-12 col-md-6">
  45. <div class="form-group">
  46. <label class="col-form-label">Country short name<span
  47. class="mandatoryFieldColor">*</span></label>
  48. <input type="text" class="form-control" name="CountryShortName"
  49. [(ngModel)]="Country.CountryShortName" #countryShortName="ngModel"
  50. [ngClass]="{ 'is-invalid': f.submitted && countryShortName.invalid }"
  51. required />
  52. <div *ngIf="f.submitted && countryShortName.invalid"
  53. class="invalid-feedback">
  54. <div
  55. *ngIf="countryShortName.errors.required || countryShortName.pristine==false">
  56. Country Short
  57. Name is required</div>
  58. </div>
  59. </div>
  60. </div>
  61. <div class="col-12 col-md-6">
  62. <div class="form-group">
  63. <label class="col-form-label">Currency name<span
  64. class="mandatoryFieldColor">*</span></label>
  65. <input type="text" class="form-control" name="Currency"
  66. [(ngModel)]="Country.Currency" #currencyName="ngModel"
  67. [ngClass]="{ 'is-invalid': f.submitted && currencyName.invalid }"
  68. required />
  69. <div *ngIf="f.submitted && currencyName.invalid" class="invalid-feedback">
  70. <div
  71. *ngIf="currencyName.errors.required || currencyName.pristine==false">
  72. Currency Name is
  73. required</div>
  74. </div>
  75. </div>
  76. </div>
  77. <div class="col-12 col-md-6">
  78. <div class="form-group">
  79. <label class="col-form-label">Currency short name<span
  80. class="mandatoryFieldColor">*</span></label>
  81. <input type="text" class="form-control" name="CurrencyShortName"
  82. [(ngModel)]="Country.CurrencyShortName" #currencyShortName="ngModel"
  83. [ngClass]="{ 'is-invalid': f.submitted && currencyShortName.invalid }"
  84. required />
  85. <div *ngIf="f.submitted && currencyShortName.invalid"
  86. class="invalid-feedback">
  87. <div
  88. *ngIf="currencyShortName.errors.required || currencyShortName.pristine==false">
  89. Currency
  90. Short Name is required</div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="col-12 col-md-12">
  95. <div class="btn-group mb-3 mt-2 cmn-btn-grp">
  96. <button *ngIf="!updateCountry" type="submit" style="margin-left:1px"
  97. class="btn btn-success">Add
  98. Country</button>
  99. <button *ngIf="updateCountry" type="submit" style="margin-left:1px"
  100. class="btn btn-success">Update
  101. Country</button>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <div class="col-12 col-md-12">
  110. <div class="card">
  111. <div class="card-header">Country Management</div>
  112. <div class="card-body position-relative">
  113. <div class="table-responsive cnstr-record product-tbl">
  114. <table class="table table-bordered heading-hvr">
  115. <thead>
  116. <tr>
  117. <th class="active">Country Name</th>
  118. <th>Short name</th>
  119. <th>Currency name</th>
  120. <th>Currency short name</th>
  121. <th width="60"> </th>
  122. <th width="60"> </th>
  123. </tr>
  124. </thead>
  125. <tbody>
  126. <tr *ngFor="let countryList of countries">
  127. <td>{{countryList.CountryName}}</td>
  128. <td>{{countryList.CountryShortName | uppercase}}</td>
  129. <td>{{countryList.Currency}}</td>
  130. <td>{{countryList.CurrencyShortName | uppercase}}</td>
  131. <td class="case-record">
  132. <button type="button" class="btn btn-info"
  133. (click)="editCountry(countryList.id)">Edit</button>
  134. </td>
  135. <td> <button type="button" class="btn btn-danger"
  136. (click)="deleteCountry(countryList.id)">Delete</button></td>
  137. </tr>
  138. </tbody>
  139. </table>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. </div>
  146. </form>
  147. </div>
Step 12
Open the app.component.html file and add the following code in this file,
  1. <app-cloud-firestore></app-cloud-firestore>
Step 13
Create a class "country.ts" and paste the code:
  1. ng g class country
  1. export class Country {
  2. CountryName: string;
  3. CountryShortName: string;
  4. Currency: string;
  5. CurrencyShortName: string;
  6. }
Step 14
Create one service "countryService"
  1. ng g s country
Paste the following code in country service.ts
  1. import { Injectable } from '@angular/core';
  2. import { HttpClient } from '@angular/common/http';
  3. import { AngularFirestore } from '@angular/fire/firestore';
  4. @Injectable({
  5. providedIn: 'root'
  6. })
  7. export class CountryService {
  8. constructor(public http: HttpClient, private angularFirestore: AngularFirestore) {
  9. }
  10. getAllCountry() {
  11. return this.angularFirestore.collection('Country').snapshotChanges();
  12. }
  13. //Adding new Country
  14. addCountryInforamtion(countryInfo) {
  15. return this.angularFirestore.collection('Country').add(countryInfo);
  16. }
  17. //Update Existing Country
  18. updateCountryInforamtion(countryid, countryInfo) {
  19. delete countryInfo.id;
  20. this.angularFirestore.doc('Country/' + countryid).update(countryInfo);
  21. }
  22. //Delete Country
  23. deleteCountry(id) {
  24. this.angularFirestore.doc('Country/' + id).delete();
  25. }
  26. }
To add data in Cloud Firestore we use .collection and .add()
To edit data in Cloud Firestore we use .doc(id) and .update()
To get data from Cloud Firestore we use .collection and .snapshotChanges()
To Delete data from Cloud Firestore we use .doc(id) and .delete()
Now the coding part is done for storing data in cloud firestore
Time to see its output
Cloud Firestore Add
Cloud Firestore Edit
Cloud Firestore Delete
Storing data in firestore
Using Real-Time Database
Step 15
Create a component "real-time-database" using the following command:
  1. ng g c real-time-database
Step 16
Now, open the real-time-database.component.ts file and add the following code in this file,
  1. import { Component, OnInit } from '@angular/core';
  2. import { Country } from '../country';
  3. import { CountryService } from '../country.service';
  4. import { AngularFireDatabase, AngularFireList } from '@angular/fire/database/database';
  5. @Component({
  6. selector: 'app-real-time-database',
  7. templateUrl: './real-time-database.component.html',
  8. styleUrls: ['./real-time-database.component.css']
  9. })
  10. export class RealTimeDatabaseComponent {
  11. updateCountry: boolean = false;
  12. countries: Country[];
  13. Country: Country = new Country();
  14. countryId = null;
  15. isToggle: boolean = false;
  16. formSubmitted: boolean;
  17. isDelete: boolean;
  18. CountryList: AngularFireList<any>;
  19. constructor(private _countryService: CountryService,
  20. private angularFireDatabase: AngularFireDatabase
  21. ) {
  22. this.getAllCountry();
  23. }
  24. getAllCountry() {
  25. this.CountryList = this.angularFireDatabase.list('Country');
  26. this.CountryList.snapshotChanges().subscribe((data: any) => {
  27. this.countries = data.map(e => {
  28. return {
  29. id: e.payload.key,
  30. ...e.payload.val()
  31. } as Country;
  32. });
  33. console.log(this.countries);
  34. });
  35. }
  36. onSubmit(f) {
  37. if (f.form.valid) {
  38. if (this.countryId == null) {
  39. this.CountryList.push({
  40. CountryName: this.Country.CountryName,
  41. CountryShortName: this.Country.CountryShortName,
  42. Currency: this.Country.Currency,
  43. CurrencyShortName: this.Country.CurrencyShortName
  44. })
  45. } else {
  46. this.CountryList.update(this.countryId, {
  47. CountryName: this.Country.CountryName,
  48. CountryShortName: this.Country.CountryShortName,
  49. Currency: this.Country.Currency,
  50. CurrencyShortName: this.Country.CurrencyShortName
  51. })
  52. }
  53. this.Country = new Country();
  54. f.submitted = false;
  55. this.formSubmitted = true;
  56. this.updateCountry = false;
  57. setInterval(() => {
  58. this.formSubmitted = false;
  59. }, 2000);
  60. }
  61. }
  62. //Edit Country method
  63. editCountry(countryId) {
  64. this.countryId = countryId;
  65. let obj: any = this.countries.filter((x: any) => {
  66. return x.id == countryId;
  67. });
  68. this.updateCountry = true;
  69. this.Country = obj[0];
  70. }
  71. // Delete Country method
  72. deleteCountry(countryId) {
  73. if (confirm('Please note! This action can NOT be undone. Are you sure you want to delete?')) {
  74. this.CountryList.remove(countryId);
  75. this.isDelete = true;
  76. setInterval(() => {
  77. this.isDelete = false;
  78. }, 2000);
  79. }
  80. }
  81. }
To add data in Real-time database we use parameter which is of type AngularDatabaseList and .push method
To edit data in Real-time database we use parameter which is of type AngularDatabaseList and .update() method
To get data from Real-time database we use .list()
To delete data from Real-time database we use parameter which is of type AngularDatabaseList and .remove()
Step 11
Open the real-time-database.component.html file and add the following code in this file,
  1. <div class="card">
  2. <form name="form" (ngSubmit)=" onSubmit(f)" #f="ngForm" novalidate>
  3. <div class="card-body pb-0">
  4. <div class="card">
  5. <div class="card-header main-search dash-search">
  6. <h1 style="text-align: center;">
  7. MANAGE COUNTRY-Using Real-time Database
  8. </h1>
  9. </div>
  10. </div>
  11. <div class="row">
  12. <div class="col-12 col-md-12">
  13. <div class="card">
  14. <div *ngIf="!updateCountry" class="card-header">
  15. Add New Country
  16. <h3 *ngIf="formSubmitted" style="text-align: center; color: green;">New Country has been
  17. added
  18. successfully...</h3>
  19. <h3 *ngIf="isDelete" style="text-align: center; color: green;">Country has been deleted
  20. successfully...</h3>
  21. </div>
  22. <div *ngIf="updateCountry" class="card-header">
  23. Update Country
  24. <h3 *ngIf="formSubmitted" style="text-align: center; color: green;">Existing Country has
  25. been updated
  26. successfully...</h3>
  27. </div>
  28. <div class="card-body">
  29. <div class="center-form">
  30. <div class="row">
  31. <div class="col-12 col-md-6">
  32. <div class="form-group">
  33. <label class="col-form-label">Name<span
  34. class="mandatoryFieldColor">*</span></label>
  35. <input type="text" class="form-control" name="CountryName" autofocus
  36. [(ngModel)]="Country.CountryName" #country="ngModel"
  37. [ngClass]="{ 'is-invalid': f.submitted && country.invalid }" required />
  38. <div *ngIf="f.submitted && country.invalid" class="invalid-feedback">
  39. <div *ngIf="country.errors.required || country.pristine==false">Country
  40. Name is required</div>
  41. </div>
  42. </div>
  43. </div>
  44. <div class="col-12 col-md-6">
  45. <div class="form-group">
  46. <label class="col-form-label">Country short name<span
  47. class="mandatoryFieldColor">*</span></label>
  48. <input type="text" class="form-control" name="CountryShortName"
  49. [(ngModel)]="Country.CountryShortName" #countryShortName="ngModel"
  50. [ngClass]="{ 'is-invalid': f.submitted && countryShortName.invalid }"
  51. required />
  52. <div *ngIf="f.submitted && countryShortName.invalid"
  53. class="invalid-feedback">
  54. <div
  55. *ngIf="countryShortName.errors.required || countryShortName.pristine==false">
  56. Country Short
  57. Name is required</div>
  58. </div>
  59. </div>
  60. </div>
  61. <div class="col-12 col-md-6">
  62. <div class="form-group">
  63. <label class="col-form-label">Currency name<span
  64. class="mandatoryFieldColor">*</span></label>
  65. <input type="text" class="form-control" name="Currency"
  66. [(ngModel)]="Country.Currency" #currencyName="ngModel"
  67. [ngClass]="{ 'is-invalid': f.submitted && currencyName.invalid }"
  68. required />
  69. <div *ngIf="f.submitted && currencyName.invalid" class="invalid-feedback">
  70. <div
  71. *ngIf="currencyName.errors.required || currencyName.pristine==false">
  72. Currency Name is
  73. required</div>
  74. </div>
  75. </div>
  76. </div>
  77. <div class="col-12 col-md-6">
  78. <div class="form-group">
  79. <label class="col-form-label">Currency short name<span
  80. class="mandatoryFieldColor">*</span></label>
  81. <input type="text" class="form-control" name="CurrencyShortName"
  82. [(ngModel)]="Country.CurrencyShortName" #currencyShortName="ngModel"
  83. [ngClass]="{ 'is-invalid': f.submitted && currencyShortName.invalid }"
  84. required />
  85. <div *ngIf="f.submitted && currencyShortName.invalid"
  86. class="invalid-feedback">
  87. <div
  88. *ngIf="currencyShortName.errors.required || currencyShortName.pristine==false">
  89. Currency
  90. Short Name is required</div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="col-12 col-md-12">
  95. <div class="btn-group mb-3 mt-2 cmn-btn-grp">
  96. <button *ngIf="!updateCountry" type="submit" style="margin-left:1px"
  97. class="btn btn-success">Add
  98. Country</button>
  99. <button *ngIf="updateCountry" type="submit" style="margin-left:1px"
  100. class="btn btn-success">Update
  101. Country</button>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <div class="col-12 col-md-12">
  110. <div class="card">
  111. <div class="card-header">Country Management</div>
  112. <div class="card-body position-relative">
  113. <div class="table-responsive cnstr-record product-tbl">
  114. <table class="table table-bordered heading-hvr">
  115. <thead>
  116. <tr>
  117. <th class="active">Country Name</th>
  118. <th>Short name</th>
  119. <th>Currency name</th>
  120. <th>Currency short name</th>
  121. <th width="60"> </th>
  122. <th width="60"> </th>
  123. </tr>
  124. </thead>
  125. <tbody>
  126. <tr *ngFor="let countryList of countries">
  127. <td>{{countryList.CountryName}}</td>
  128. <td>{{countryList.CountryShortName | uppercase}}</td>
  129. <td>{{countryList.Currency}}</td>
  130. <td>{{countryList.CurrencyShortName | uppercase}}</td>
  131. <td class="case-record">
  132. <button type="button" class="btn btn-info"
  133. (click)="editCountry(countryList.id)">Edit</button>
  134. </td>
  135. <td> <button type="button" class="btn btn-danger"
  136. (click)="deleteCountry(countryList.id)">Delete</button></td>
  137. </tr>
  138. </tbody>
  139. </table>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. </div>
  146. </form>
  147. </div>
Step 12
Open the app.component.html file and add the following code in this file,
  1. <app-real-time-database></app-real-time-database>
Now it's time to see the output of real time database
Real-time Database Add
Real-time Database Edit
Real-time Database Delete

Conclusion

In this article, we have seen how to perform CRUD operations in Angular 8 with Firebase Cloud Firestore and Real-Time Database.
Please give your valuable feedback/comments/questions about this article.