Cloud Firestore helps us store data in the cloud. It supports offline mode so our app will work fine (write, read, listen to, and query data) whether device has internet connection or not, it automatically fetches changes from our database to Firebase Server. We can structure data in our ways to improve querying and fetching capabilities. This tutorial shows you how to work with Firebase Firestore along with an Angular app that can do CRUD Operations.
Related Posts:
– Angular 8 Firebase tutorial: Integrate Firebase into Angular 8 App with @angular/fire
– Angular 8 Firebase CRUD operations with @angular/fire
– Angular 8 – Upload/Display/Delete files to/from Firebase Storage using @angular/fire
Contents
Technology
– Angular 8
– @angular/fire 5.1.2
– firebase 5.10.1
Video
Firebase Firestore with @angular/fire
Set up the Firebase Project & Install @angular/fire
Please visit this post to know step by step.
The only different for this tutorial is that, we use Firebase Firestore instead of Firebase Realtime Database:
Firebase Firebase CRUD operations for Object
Create an object binding/ Retrieve
item: AngularFirestoreDocument; // db: AngularFirestore this.item = db.doc('item'); // or Observable item = db.doc('item').valueChanges();
Create
// db: AngularFirestore const itemRef = db.doc('item'); // set() for destructive updates itemRef.set({ name: 'grokonez'});
Update
// db: AngularFirestore const itemRef = db.doc('item'); itemRef.update({ url: 'grokonez.com'});
Delete
// db: AngularFirestore const itemRef = db.doc('item'); itemRef.delete();
Firebase Firebase CRUD operations for List of Objects
Create a list binding/ Retrieve
– 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();
Create
// db: AngularFirestore const itemsRef = db.collection('items'); itemsRef.add({ site: 'grokonez.com' });
Update
// 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: 'grokonez.com' });
Delete
// 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); });
Configure offline persistence
By default, offline persistence is disabled. To enable it, call enablePersistence()
method:
firebase.firestore().enablePersistence() .catch(err => { if (err.code == 'failed-precondition') { // only be enabled in one tab at a a time (multiple tabs open) } else if (err.code == 'unimplemented') { // browser does not support all of the features required to enable persistence } });
Firebase Firestore CRUD in Angular 8 App using @angular/fire
Project Overview
Goal
We will build an Angular 8 Firebase App using @angular/fire
that can:
– add/remove Customer
– show all Customers
– update Customer’s status
to Firebase Firestore.
Project Structure
– environment.ts configure information to connect with Firebase Project.
– customer.ts defines Customer
class data model.
– customer.service.ts defines CustomerService
that uses @angular.fire
to interact with Firebase.
– 3 Angular components:
+ create-customer
for creating new item.
+ customer-details
shows item detais
+ customers-list
contains list of items, this is parent component of customer-details
– app-routing.module.ts
defines how we route Angular components.
– app.module.ts
declares and imports necessary environment & modules.
Step by Step
Set up the Firebase Project & Install @angular/fire
Please visit this post to know step by step.
Add Firebase config to environments variable
Open /src/environments/environment.ts, add your Firebase configuration that we have saved when Popup window was shown:
export const environment = { ... firebase: { apiKey: 'xxx', authDomain: 'gkz-angular-firebase.firebaseapp.com', databaseURL: 'https://gkz-angular-firebase.firebaseio.com', projectId: 'gkz-angular-firebase', storageBucket: 'gkz-angular-firebase.appspot.com', messagingSenderId: '123' } };
Create Service & Components
Run the commands below:
– ng g s customers/Customer
– ng g c customers/CustomerDetails
– ng g c customers/CustomersList
– ng g c customers/CreateCustomer
Setup @NgModule
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { FormsModule } from '@angular/forms'; import { AngularFireModule } from '@angular/fire'; import { AngularFirestoreModule, FirestoreSettingsToken } from '@angular/fire/firestore'; import { environment } from '../environments/environment'; import { AppComponent } from './app.component'; import { CustomerDetailsComponent } from './customers/customer-details/customer-details.component'; import { CustomersListComponent } from './customers/customers-list/customers-list.component'; import { CreateCustomerComponent } from './customers/create-customer/create-customer.component'; @NgModule({ declarations: [ AppComponent, CustomerDetailsComponent, CustomersListComponent, CreateCustomerComponent ], imports: [ BrowserModule, FormsModule, AppRoutingModule, AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule ], providers: [{ provide: FirestoreSettingsToken, useValue: {} }], bootstrap: [AppComponent] }) export class AppModule { }
Create Model Class
customer.ts
export class Customer { key: string; name: string; age: number; active = true; }
The key
field is important for updating item.
Create Data Service
customer.service.ts
import { Injectable } from '@angular/core'; import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'; import { Customer } from './customer'; @Injectable({ providedIn: 'root' }) export class CustomerService { private dbPath = '/customers'; customersRef: AngularFirestoreCollection= null; constructor(private db: AngularFirestore) { this.customersRef = db.collection(this.dbPath); } createCustomer(customer: Customer): void { this.customersRef.add({...customer}); } updateCustomer(key: string, value: any): Promise { return this.customersRef.doc(key).update(value); } deleteCustomer(key: string): Promise { return this.customersRef.doc(key).delete(); } getCustomersList(): AngularFirestoreCollection { return this.customersRef; } deleteAll() { this.customersRef.get().subscribe( querySnapshot => { querySnapshot.forEach((doc) => { doc.ref.delete(); }); }, error => { console.log('Error: ', error); }); } }
Create Component for item Details
customer-details.component.ts
import { Component, OnInit, Input } from '@angular/core'; import { CustomerService } from '../customer.service'; import { Customer } from '../customer'; @Component({ selector: 'app-customer-details', templateUrl: './customer-details.component.html', styleUrls: ['./customer-details.component.css'] }) export class CustomerDetailsComponent implements OnInit { @Input() customer: Customer; constructor(private customerService: CustomerService) { } ngOnInit() { } updateActive(isActive: boolean) { this.customerService .updateCustomer(this.customer.key, { active: isActive }) .catch(err => console.log(err)); } deleteCustomer() { this.customerService .deleteCustomer(this.customer.key) .catch(err => console.log(err)); } }
customer-details.component.html
{{customer.name}}{{customer.age}}{{customer.active}}
Create Component to show List of Items
customers-list.component.ts
import { Component, OnInit } from '@angular/core'; import { CustomerService } from '../customer.service'; import { map } from 'rxjs/operators'; @Component({ selector: 'app-customers-list', templateUrl: './customers-list.component.html', styleUrls: ['./customers-list.component.css'] }) export class CustomersListComponent implements OnInit { customers: any; constructor(private customerService: CustomerService) { } ngOnInit() { this.getCustomersList(); } getCustomersList() { this.customerService.getCustomersList().snapshotChanges().pipe( map(changes => changes.map(c => ({ key: c.payload.doc.id, ...c.payload.doc.data() }) ) ) ).subscribe(customers => { this.customers = customers; }); } deleteCustomers() { this.customerService.deleteAll(); } }
In the code above, we use snapshotChanges()
with RxJS map()
operator to get the id
of each item and assign to key
field.
customers-list.component.html:
Customers
We pass each customer
item data to customer-details
component.
Create Component to save item
create-customer.component.ts
import { Component, OnInit } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { Customer } from '../customer'; import { CustomerService } from '../customer.service'; @Component({ selector: 'app-create-customer', templateUrl: './create-customer.component.html', styleUrls: ['./create-customer.component.css'] }) export class CreateCustomerComponent implements OnInit { customer: Customer = new Customer(); submitted = false; constructor(private customerService: CustomerService) { } ngOnInit() { } newCustomer(): void { this.submitted = false; this.customer = new Customer(); } save() { this.customerService.createCustomer(this.customer); this.customer = new Customer(); } onSubmit() { this.submitted = true; this.save(); } }
create-customer.component.html:
Create Customer
You submitted successfully!
Define App Routing Module
app-routing.module.ts
import { CreateCustomerComponent } from './customers/create-customer/create-customer.component'; import { CustomersListComponent } from './customers/customers-list/customers-list.component'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'customers', pathMatch: 'full' }, { path: 'customers', component: CustomersListComponent }, { path: 'add', component: CreateCustomerComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
app.component.html:
{{title}}
{{description}}
To understand how to use Angular Routing Module, please visit:
How to work with Angular Routing – Spring Boot + Angular 4
Run & Check Result
– Run Angular App with command: npm start
.
– Open browser with url http://localhost:4200/
.
Result in Firestore console:
Source Code
Conclusion
Now we’ve known how to connect Angular App with Firebase Firestore, how to make CRUD operations with Firestore for Object or List of Objects. We also created an Angular 8 Application that can save, receive, update, delete items with Firestore Database.
Happy learning!
Thanks a lot, its really helpful but i have been trying to update record using a form but to no avail. I need help please, i am a novice of angular.
Hello, for the delete function, I keep getting key undefined in my component typescript. Any idea why?
Hi I am getting the following error while serving the application
This likely means that the library (@angular/fire/firestore) which declares AngularFirestore has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library’s authors to see if
the library is expected to be compatible with Ivy.