Starting With Google Cloud Firestore Database With Angular

What is the cloud Firestore?

 
Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. Unlike an SQL database, there are no tables or rows. Instead, you store the data in documents organized into a collection.
 
cloud Firestore
 
All documents must be stored in collections. Documents can contain subcollections and nested objects, both of which can include primitive fields (like strings) or complex objects (like lists).
 
Collections and documents are created implicitly in Cloud Firestore. Simply, assign the data to a document within a collection. If either the collection or document does not exist, Cloud Firestore creates it.
 
Document
In Cloud Firestore, the unit of storage is the document. A document is a lightweight record that contains fields that map to values.
 
Collections
Documents live in collections, which are simply containers for documents.
 
cloud Firestore
 
Here, users_data is the collection, and the document name will be obtained by auto key value.
 
(Source Credit Google Cloud Platform)
 
So now, it is time for some action. We will see how to create a Firestore document and how to insert/fetch the data from the Firestore database.
 
Prerequisites
First, execute the following command.
npm install firebase angularfire2 –save
 
Cloud Firestore Setup
 
After logging in to Firebase console account,  follow the below steps.
  • Create Project.
  • Navigate to the Database tab.
     
    cloud Firestore
     
  • Select Cloud Firestore Database and create a project in test mode.
     
    cloud Firestore
     
  • Now, add a collection by clicking Add Collection.
     
    cloud Firestore
     
    cloud Firestore
     
    cloud Firestore
     
Setting up Angular Application
  • First, get the configuration to connect Firestore from Angular by clicking the "Setting" button.
     
    cloud Firestore
     
  • Now, store all the configuration information.
     
    cloud Firestore
Environments.ts
  1. export const environment = {  
  2.   production: false,  
  3.   firebase: {  
  4.     apiKey: 'your key',  
  5.     authDomain: 'your auth domain',  
  6.     databaseURL: 'db url',  
  7.     projectId: 'project id',  
  8.     storageBucket: '',  
  9.     messagingSenderId: 'sender id'  
  10.   }};  
Now, first initialize your application with Firestore configuration in the module.ts file, as shown below.
  1. import { environment } from '../environments/environment';  
  2. import { AngularFireModule } from 'angularfire2';  
  3. import { AngularFirestoreModule } from 'angularfire2/firestore';  
  4.   
  5. imports: [  
  6.     BrowserModule,  
  7.     AngularFireModule.initializeApp(environment.firebase),  
  8.     AngularFirestoreModule  
  9.   ],  
First, import AngularFireModule and AngularFirestoreModule from AngularFire2 and then, initialize your application in import array with the configuration which we had stored in environment.ts.
 
Now, let us create the service to fetch the data from the Firestore database. And also, create a user class to provide some data structure. We can generate the service using the following command.
 
ng g s firestore-data
 
user.ts
  1. export class User {  
  2. public constructor(public id: string,public firstname: string,public lastname: string,public mobile_no: string) {  
  3.   }  
  4. }  
firestore-data.service.ts
 
Import the following packages to fetch the data from the server and store it in our observable.
  1. import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';  
  2.   
  3. import { Observable } from 'rxjs/Observable';  
  4. import { User } from './user';  
Now, create a collection which is type of our user class.
 
users: Observable<User[]>;
 
Then, create the instance of AngularFirestore in the constructor. And, write the following code to fetch the data from user collection.
  1. this.users = this._afs.collection('Users').valueChanges();  
Collection without id
 
cloud Firestore
 
From the above valueChanges() method, we can fetch the data but not that auto-id. Which we will require to delete and update the record. So, to fetch that auto-id field with data, we should use snapshotChanges(), as shown below.
  1. this.users = this._afs.collection('Users').snapshotChanges().map(  
  2.       changes => {  
  3.         return changes.map(  
  4.           a => {  
  5.             const data = a.payload.doc.data() as User;  
  6.             data.id = a.payload.doc.id;  
  7.             return data;  
  8.           });  
  9.       });  
Collection with id
 
cloud Firestore
 
Now, it is time to display our data on our app.component file. To do so, first, let me inject our firestore-data.service in app.component.ts file, as shown below.
  1. import { FirestoreDataService } from './firestore-data.service';  
  2. import { User } from './user';  
  3. arr: User[] = [];  
  4. constructor(public _data: FirestoreDataService) {   }  
And now, call your getUsers method inside ngOnInit method of component’s life cycle event hook, as shown below.
  1. ngOnInit() {  
  2.     this._data.getUsers().subscribe(  
  3.       (user: User[]) => {  
  4.         this.arr = user;  
  5.         console.log(this.arr);  
  6.       }  
  7.     );  
  8.   }  
And on app.component.html, let’s loop through the array and display all the users on our page.
  1. <div class="container"  *ngIf="arr.length>0;else noData">  
  2.   <ul *ngFor="let item of arr" class="list-group">  
  3.     <li class="list-group-item">  
  4.       <strong>{{item.firstname}}{{item.lastname}}</strong> : {{item.mobile_no}} </li>  
  5.   
  6.   </ul>  
  7.   
  8. </div>  
  9. <div class="container">  
  10. <ng-template #noData>  
  11.   <hr>  
  12.   <h5>There are no users to display</h5>  
  13. </ng-template>  
  14. </div>  
cloud Firestore
 
Add New User
 
For adding a new user to the collection, we will need to adjust 3 things, (i) app.component.html (ii) app.component.ts (iii) firestore-data.service.ts
Html
  1. <div class="container">  
  2.   <h1>Add New User</h1>  
  3.   <form (ngSubmit)="userSubmit()" #addform="ngForm">  
  4.     <div class="form-group">  
  5.       <label for="firstname">FirstName</label>  
  6.       <input type="text" [(ngModel)]="model.firstname" name="firstname" class="form-control" id="firstname" required #firstname="ngModel">  
  7.     </div>  
  8.     <div [hidden]="firstname.valid || firstname.pristine" class="alert alert-danger">  
  9.       Firstname is required  
  10.     </div>  
  11.     <div class="form-group">  
  12.       <label for="lastname">LastName</label>  
  13.       <input type="text" [(ngModel)]="model.lastname" name="lastname" class="form-control" id="lastname" required #lastname="ngModel">  
  14.     </div>  
  15.     <div [hidden]="lastname.valid || lastname.pristine" class="alert alert-danger">  
  16.       Lastname is required  
  17.     </div>  
  18.     <div class="form-group">  
  19.       <label for="mobile_no">Mobile Number</label>  
  20.       <input type="text" [(ngModel)]="model.mobile_no" name="mobile_no" class="form-control" id="mobile_no" required #mobileno="ngModel">  
  21.     </div>  
  22.     <div [hidden]="mobileno.valid || mobileno.pristine" class="alert alert-danger">  
  23.       Mobile number is required  
  24.     </div>  
  25.   <button type="submit" class="btn btn-default form-control" [disabled]="!addform.form.valid">Add User</button>  
  26.   </form>  
  27. </div>  
TS
  1. model = { firstname: '', lastname: '', mobile_no: '' };  
  2. userSubmit() {  
  3.     this._data.addUser(this.model);  
  4.     this.model.firstname = '';  
  5.     this.model.lastname = '';  
  6.     this.model.mobile_no = ''; }  
Service
 
In our Service file, first, we need to create usersCollection which is an instance of AngularFirestoreCollection.
  1. userscollection: AngularFirestoreCollection<User>; 
And initialize this userscollection inside the constructor, as shown below.
  1. this.userscollection = this._afs.collection('Users', x => x.orderBy('firstname''asc'));  
Here, I have used orderBy operator also to sort the data by the first name in ascending order.
 
Then finally, the addUser method is used.
  1. addUser(user) {  
  2.     this.userscollection.add(user);  
  3.   }  
Delete User
 
Again, in order to delete the particular user from the list, we will require to change the 3 files. (i) app.component.html (ii) app.component.ts (iii) firestore-data.service.ts
 
HTML
 
Add a Delete button to app.component.html, as shown below.
  1. <a (click)="onDelete(item)" >  
  2.         <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>  
  3.       </a>  
TS
 
Create onDelete() method in app.component.ts, as shown below.
  1. onDelete(user) {  
  2.     this._data.deleteUser(user);  
  3.   }  
Service
 
First, we will create an instance of AngularfirestoreDocument, as shown below.
userDoc: AngularFirestoreDocument<User>;
 
Then, create deleteUser method inside the firestore-data.service file.
  1. deleteUser(user) {  
  2.     this.userDoc = this._afs.doc(`Users/${user.id}`);  
  3.     this.userDoc.delete();  
  4.   }  
final firestore-data.service.ts
  1. import { Injectable } from '@angular/core';  
  2. import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';  
  3.   
  4. import { Observable } from 'rxjs/Observable';  
  5. import { User } from './user';  
  6.   
  7. @Injectable()  
  8. export class FirestoreDataService {  
  9.   userscollection: AngularFirestoreCollection<User>;  
  10.   users: Observable<User[]>;  
  11.   userDoc: AngularFirestoreDocument<User>;  
  12.   constructor(public _afs: AngularFirestore) {  
  13.     //this.users = this._afs.collection('Users').valueChanges();  
  14.   
  15.     this.userscollection = this._afs.collection('Users', x => x.orderBy('firstname''asc'));  
  16.     this.users = this.userscollection.snapshotChanges().map(  
  17.       changes => {  
  18.         return changes.map(  
  19.           a => {  
  20.             const data = a.payload.doc.data() as User;  
  21.             data.id = a.payload.doc.id;  
  22.             return data;  
  23.           });  
  24.       });  
  25.   }  
  26.   getUsers() {  
  27.     return this.users;  
  28.   }  
  29.   addUser(user) {  
  30.     this.userscollection.add(user);  
  31.   }  
  32.   deleteUser(user) {  
  33.     this.userDoc = this._afs.doc(`Users/${user.id}`);  
  34.     this.userDoc.delete();  
  35.   }  
  36. }  
final app.component.html
  1. <div class="container">  
  2.   <h1>Add New User</h1>  
  3.   <form (ngSubmit)="userSubmit()" #addform="ngForm">  
  4.     <div class="form-group">  
  5.       <label for="firstname">FirstName</label>  
  6.       <input type="text" [(ngModel)]="model.firstname" name="firstname" class="form-control" id="firstname" required #firstname="ngModel">  
  7.     </div>  
  8.     <div [hidden]="firstname.valid || firstname.pristine" class="alert alert-danger">  
  9.       Firstname is required  
  10.     </div>  
  11.     <div class="form-group">  
  12.       <label for="lastname">LastName</label>  
  13.       <input type="text" [(ngModel)]="model.lastname" name="lastname" class="form-control" id="lastname" required #lastname="ngModel">  
  14.     </div>  
  15.     <div [hidden]="lastname.valid || lastname.pristine" class="alert alert-danger">  
  16.       Lastname is required  
  17.   
  18.     </div>  
  19.     <div class="form-group">  
  20.       <label for="mobile_no">Mobile Number</label>  
  21.       <input type="text" [(ngModel)]="model.mobile_no" name="mobile_no" class="form-control" id="mobile_no" required #mobileno="ngModel">  
  22.     </div>  
  23.     <div [hidden]="mobileno.valid || mobileno.pristine" class="alert alert-danger">  
  24.       Mobile number is required  
  25.     </div>  
  26.     <button type="submit" class="btn btn-default form-control" [disabled]="!addform.form.valid">Add User</button>  
  27.  </form>  
  28. </div>  
  29. <hr>  
  30. <div class="container" *ngIf="arr.length>0;else noData">  
  31.   <ul *ngFor="let item of arr" class="list-group">  
  32.     <li class="list-group-item">  
  33.       <strong>{{item.firstname}}{{item.lastname}}</strong> : {{item.mobile_no}}  
  34.   
  35.       <a (click)="onDelete(item)" >  
  36.         <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>  
  37.       </a>  
  38.     </li>  
  39.   </ul>  
  40. </div>  
  41. <div class="container">  
  42.   <ng-template #noData>  
  43.     <hr>  
  44.     <h5>There are no users to display</h5>  
  45.   </ng-template>  
  46. </div>  
final app.component.ts
  1. import { Component, OnInit } from '@angular/core';  
  2. import { FirestoreDataService } from './firestore-data.service';  
  3. import { User } from './user';  
  4.   
  5. @Component({  
  6.   selector: 'app-root',  
  7.   templateUrl: './app.component.html',  
  8.   styleUrls: ['./app.component.css']  
  9. })  
  10. export class AppComponent implements OnInit {  
  11.   arr: User[] = [];  
  12.   model = { firstname: '', lastname: '', mobile_no: '' };  
  13.   ngOnInit() {  
  14.     this._data.getUsers().subscribe(  
  15.       (user: User[]) => {  
  16.         this.arr = user;  
  17.         console.log(this.arr);  
  18.       }  
  19.     );  
  20.   }  
  21.   constructor(public _data: FirestoreDataService) {  
  22.   }  
  23.   userSubmit() {  
  24.     this._data.addUser(this.model);  
  25.     this.model.firstname = '';  
  26.     this.model.lastname = '';  
  27.     this.model.mobile_no = '';  
  28.   }  
  29.   onDelete(user) {  
  30.     this._data.deleteUser(user);  
  31.   }  
  32. }  


Similar Articles