In this tutorial, we’ll learn and demonstrate the latest AngularFire 7.2.0, to perform Angular Firebase CRUD operation. The Firebase is one of the most popular and used serverless technology from Google. Allows front-end developers to focus mostly on the frontend instead of on the backend. The Google Firebase offers a wide range of backend services like hosting, cloud Firestore, Analytics, cloud messaging, cloud storage, and many more.
What we are learning on Angular Firebase?
In this Angular Firebase tutorial, we will be focusing on Angular Firestore and will perform the following Firebase CRUD operation using the latest angularFire library.
- Retrieving a collection of records from a collection called books.
- Adding a new record to books collection.
- Deleting/editing a document or record.
- Editing a single field of a document like the price of a book on blur event on input.
- Performing firebase query, search by a field
- Retrieving a document by id
Firebase CRUD App Screenshot of our Angular book apps.
We can use Firebase Firestore to store data on Google cloud storage. With Firebase we can easily do CRUD operations and Firebase also provides a different option for authentication for Firebase CRUD apps.
Setting up and configuring Firebase CRUD apps
Before using Firebase, we need to configure our application. Let’s first create Firebase angular project.
ng new firebaseCRUDApp
cd firebaseCRUDApp
Setting Firebase project is simple, but it has some steps to be carried out. We’ll divide the configuration section into three parts, otherwise, it will messy and long.
- Creating Firebase project and configuring project at Firebase console.
- Installing AngularFire and adding Bootstrap UI and icon.
- Creating components, services to implement Firebase activities
Create and configure our project in the Firebase console.
Let open the browser and type https://firebase.google.com, we need to create a project on firebase and configure the Google cloud Firestore database for it.
In the Firebase console, we need to click on Add Project to create a new project and we should give the name of our project, In our case let say book as a project name.
Once we add our project name, let’s click on the continue button, it will take us to these options. For this example we don’t need Google Analytics, let’s disable it.
Clicking on the Create project will create a Firebase project for us.
Create a Firebase web project
Now we need Firebase configuration for our web application. Our front-end application needs the web configuration to connect to the Firebase project at Google Firestore.
In the Firebase project dashboard, we have many options and let’s click on the “Web” icon as shown in the image below.
Once, we click on the web icon, we have to provide a nickname for our app. You can use any name of your choice. Here we will use the name bookWebApp, the same name as ours. Click on the “Register App” button.
Add Firebase web config value in the Front-end project
We need to copy this our firebase project API key, and past it in our client project src/environments/environment.ts as shown in the code snippet below. The below code is just for demo, you can replace it with your own API code.
export const environment = {
production: false,
firebase: {
apiKey: "AIzffdfdf--jSe9ys",
authDomain: "book-sss.firebaseapp.com",
projectId: "book-sss4db",
storageBucket: "book-8db.appspot.com",
messagingSenderId: "98759698508",
appId: "1:959685345:web:30a3c6bf6d8fca5837b6cc"
}
};
Create cloud firestore database
We have almost finished our firebase project configure in firebase.com, now we need to create our firebase database. Let’s click on the Firestore database icon as shown below.
Click on create database will ask us for production or test mode and this is an example. Let’s select test mode, now our database is ready. In later articles, we will learn how to perform Firebase operations using AngularFire.
Installing AngularFire and Adding the Bootstrap library
We had successfully set up the Firebase project at the Firebase cloud console. Let’s now add Bootstrap and bootstrap icon libraries to our project.
ng add @ng-bootstrap/ng-bootstrap
npm install bootstrap-icons --save
To use bootstrap icons we need to import, the Bootstrap-icon style in style.scss or style.css file.
/* Importing Bootstrap SCSS file. */
@import '~bootstrap/scss/bootstrap';
@import '~bootstrap-icons/font/bootstrap-icons';
Install AngularFire library to our project
We need to install the angularFire library to perform the Firebase CRUD operation in our Angular application. The angularFire is the Angular library for Firebase, the latest AngularFire 7 has lots of new changes, we can easily perform Firebase CRUD operations using it.
Let’s run the command below to add the Firebase project to our Angular project
ng add @angular/fire
While running the above command will take a few minutes, asking you to select some options as shown in the image below.
- First, we have to select what feature we want to add to our project, for us we have to select Firestore.
- On select Firestore, will ask you to login to Firebase and if you are already connected then it will take automatically login.
- At last, we have to select the project name, in our case Firebase console project books, select it.
Once we successfully add the AngularFire library, we need to set the Firebase configuration in the app.module.ts file to connect to the Firebase project in the Google Firebase cloud.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { getFirestore, provideFirestore } from '@angular/fire/firestore';
import { environment } from 'src/environments/environment';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
BooksComponent,
BookComponent,
HomeComponent,
EditBookComponent,
SearchComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
NgbModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideFirestore(() => getFirestore()),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
We also need Forms, so we had added FormsModule to use the Angular template form for adding and editing a book record. The Firebase configuration setting is different from the previous version of AngularFire, where we use AngularFireModule, this is not the case in the latest version.
We have to use the provideFirebaseApp and provideFireStore function to connect to our Firebase project.
Creating all components, book service for Firebase CRUD
To implement the firebase CRUD operation, we will need a form that allows us to add/edit book records. All book record activities like adding a new book, deleting, updating, and listing are done in our book service, which is consumed by components. Let’s add all components needed for Firebase CRUD operation.
ng generate component components/home
ng generate component components/book
ng generate component components/books
ng generate component components/search
In our home component contains two parts.
- Book component for adding new book records
- Books component, list of books already added.
We also need the book service, and modal called edit-book modal to implement editing of a record.
ng generate component modal/editBook
ng generate service services/book
We also need a model for the book, so that we can implement a strict type, to minimize error. Let create folder models in src/app and add a file called book.model.ts file.
export interface IBook {
id?: string;
name : string;
author : string;
genre : string;
price : number;
}
Configure routing of Firestore application, we have two navigation buttons, home and search component. In the app.routing.module.ts, add routing configuration for both.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { SearchComponent } from './components/search/search.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'search', component: SearchComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
The home component has two child components, one for adding new records and the other for listing all records. Let’s edit the home.component.html file
<div class="container">
<div class="row">
<div class="col-md-4">
<app-book></app-book>
</div>
<div class="col-md-7">
<app-books></app-books>
</div>
</div>
</div>
In the app.component.html template, let’s add the navigation part.
<div class="jumbotron">
<h2 style="text-align:center;">
Book Collection
</h2>
<button type="button" routerLink="" class="btn btn-link">
Home
</button>
<button type="button" routerLink="search" class="btn btn-link">
Search
</button>
</div>
<router-outlet></router-outlet>
Angular Firestore CRUD operation
Let implement Angular Firestore CRUD operation, as we had completed all configuration and setting up of the Firebase project. The Firestore CRUD stands for (Create, read, update and delete).
Firebase Create a record
We’ll be implementing one by one CRUD operation, let first perform creating a new record in Firebase. In our services/book.service.ts edit code to implement create operation.
import { Injectable } from '@angular/core';
import {
Firestore, addDoc, collection, collectionData,
doc, docData, deleteDoc, updateDoc, DocumentReference, setDoc
} from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { IBook } from '../models/book.model';
@Injectable({
providedIn: 'root'
})
export class BookService {
constructor(private firestore: Firestore) { }
addBook(book: IBook) {
const booksRef = collection(this.firestore, 'books');
return addDoc(booksRef, book);
}
}
We need to import Firestore from ‘@angular/fire/firestore’ and also need to declare it in the constructor. We also import many objects and classes from @angular/fire/firestore, we need all this later.
First, we need a reference to our collection books, which we can get from a collection by passing two-argument the Firestore and the name of the collection in our case books. Now we use addDoc to add create a new record book using the reference of a collection as shown above.
Create a form for adding new book record
We need a form, to add a new book record, here is a screenshot for adding a record in Firestore.
In the book.component.ts file, we need to import BookService and inject it into the book constructor. Let edit the book component to consume the BookService to add a new record.
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss']
})
export class BookComponent implements OnInit {
book: IBook = { name: '', author: '', genre: '', price: 0 };
constructor(private bookService: BookService) { }
ngOnInit() {
}
onSubmit(form: NgForm) {
this.bookService.addBook(form.value).
then(() => form.reset());
}
}
Let add a template form, to allow users to input a book record.
<div>
<h4>Add new book record</h4>
<form #bookForm="ngForm" (ngSubmit)="onSubmit(bookForm)">
<div class="form-group">
<label>Book Name</label>
<input class="form-control" name="name" #name="ngModel"
[(ngModel)]="book.name" placeholder="Book Name" required>
</div>
<div class="form-group">
<label>Author</label>
<input class="form-control" name="author" #name="ngModel"
[(ngModel)]="book.author" placeholder="Author" required>
</div>
<div class="form-group">
<label>Genre</label>
<select class="form-control" name="genre" #name=ngModel
[(ngModel)]="book.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="bi bi-currency-dollar"></i>
</div>
<input class="form-control" name="price" #name="ngModel"
[(ngModel)]="book.price" placeholder="Price" required>
</div>
</div>
<div class="form-group float-right">
<button type="submit" class="btn btn-success"
[disabled]="!bookForm.valid" [disabled]="bookForm.invalid">
<i class="bi bi-plus"></i>Add Book</button>
</div>
</form>
</div>
Clicking on submit button will add a record to Firestore, It is best to keep API access outside of the component. We use service to access API calls to Firebase, service acts as state management allows us to share service code among different components.
Retrieve Firestore data collection
In the books component, we are displaying all book records of collection books. Let first edit the book.service.ts file to retrieve all documents from a collection.
getBooks(): Observable<IBook[]> {
const booksRef = collection(this.firestore, 'books');
return collectionData(booksRef, { idField: 'id' }) as Observable<IBook[]>;
}
We use collectionData to get all records from collections, to get documents with the id we need to add { idField: ‘id’ }. In the previous version of AngularFire is a little bit of extra work, now getting documents with id is easy. The getBooks() return observable of type IBook array, we are consuming this observable in books component.
Now in the books.component.ts file, we need to import and inject BookService to consume the getBooks() method from BookService and let edit this component.
import { Component, OnInit } from '@angular/core';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { EditBookComponent } from '../modal/edit-book/edit-book.component';
@Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.scss']
})
export class BooksComponent implements OnInit {
books: IBook[] = [];
constructor(
private bookService: BookService,
private modal: NgbModal) { }
ngOnInit() {
this.bookService.getBooks().subscribe((res: IBook[]) => {
this.books = res;
})
}
editModal(book: IBook) {
const modalRef = this.modal.open(EditBookComponent, {
size: 'lg',
centered: true,
windowClass: 'dark-modal',
});
modalRef.componentInstance.id = book.id;
}
deleteBook(book: IBook) {
if (confirm('Are you sure to delete this record ?') == true) {
this.bookService.deleteBook(book).then(() =>
console.log('delete successful'));
}
}
}
In this component typescript, we also have code to edit and delete records. For time being let only focus on ngOnit to get books record. Now in the book.component.html template, let add a table to display the book’s records.
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Author</th>
<th scope="col">Genres</th>
<th scope="col">Price</th>
<th scope="col">Edit</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody *ngIf="books">
<tr *ngFor="let book of books; index as i">
<th scope="row">{{ i+1 }}</th>
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.genre }}</td>
<td>{{ book.price }}</td>
<td>
<i class="bi bi-pencil-square" style="color: green;"
(click)="editModal(book)"></i>
</td>
<td>
<i class="bi bi-trash" (click)="deleteBook(book)" style="color: red;"></i>
</td>
</tr>
</tbody>
</table>
Firestore CRUD delete operation
In the books component, we have a list of all books from the collection books. We also add pencil icons to edit and delete icons to delete on each book on the list. Clicking on the delete icon will invoke delete a record on the collection list. But first, we need to add the corresponding delete function in the book.service.ts file, let’s add it.
deleteBook(book: IBook) {
const bookDocRef = doc(this.firestore, `books/${book.id}`);
return deleteDoc(bookDocRef);
}
The consumer of this the deleteBook() method is already added in the previous section books component. We only have to pass the id of the book record to delete.
Firebase CRUD update and set operation
We have completed CRUD operations like create, delete and read. But now we are left with an update and set operation of a record. Let do this in our edit-book modal component, as shown in the image below.
Before implementing the edit book modal, we need to add it corresponding update and set method in the book.service.ts file. Let add set, update and retrieve the Firebase document by id operations in the book.service.ts file.
getBookByID(id: string) {
const bookRef = doc(this.firestore, `books/${id}`);
return docData(bookRef, { idField: 'id' }) as Observable<IBook>;
}
updateBook(book: IBook) {
const bookDocRef = doc(this.firestore, `books/${book.id}`);
return setDoc(bookDocRef, book);
}
modifyBookPrice(book: IBook, amount: number) {
const bookDocRef = doc(this.firestore, `books/${book.id}`);
return updateDoc(bookDocRef, { price: amount });
}
setDoc | updateDoc |
Destructively updates a document’s data, if the document didn’t exist it will create a new document. | Non-destructively updates a document’s data. Edit field or property of the document. |
In the books component, we have an edit icon, and clicking on it will invoke editModal(book: IBook) which in turn opens modal for edit book with an id of that book.
Now in the edit book modal, we are performing the following activities.
- On blur on price input will set new price value for book record.
- Clicking on Update Book will update the book to a new value that we have entered in a form.
Let’s edit the edit-book.component.ts file, we also need to retrieve a book record by using its id
import { Component, Input, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { IBook } from 'src/app/models/book.model';
import { BookService } from 'src/app/services/book.service';
@Component({
selector: 'app-edit-book',
templateUrl: './edit-book.component.html',
styleUrls: ['./edit-book.component.scss']
})
export class EditBookComponent implements OnInit {
@Input() id: string;
book: IBook;
constructor(
private bookService: BookService,
public activeModal: NgbActiveModal)
{ }
ngOnInit() {
if (this.id)
this.bookService.getBookByID(this.id).subscribe(res => {
this.book = res
});
}
onUpdate() {
this.bookService.updateBook(this.book).then(() => {
this.activeModal.close();
console.log('Data add successfully');
})
}
setPrice(book: IBook, price: number) {
this.bookService.modifyBookPrice(book, price)
}
}
We need to inject BookService in the edit-book component, now let’s edit the edit-book component template to add a form for edit and set.
<div *ngIf="book" class="container">
<h4>Edit book record</h4>
<form #bookForm="ngForm" (ngSubmit)="onUpdate()">
<div class="form-group">
<label>Book Name</label>
<input class="form-control" name="name" #nameCtrl="ngModel"
[(ngModel)]="book.name" placeholder="Book Name" required>
</div>
<div class="form-group">
<label>Author</label>
<input class="form-control" name="author" #authorCtrl="ngModel"
[(ngModel)]="book.author" placeholder="Author" required>
</div>
<div class="form-group">
<label>Genre</label>
<select class="form-control" name="genre" #genreCtrl=ngModel
[(ngModel)]="book.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="bi bi-currency-dollar"></i>
</div>
<input class="form-control" name="price" #priceCtrl="ngModel"
(blur)="setPrice(book, priceCtrl.value)"
[(ngModel)]="book.price" placeholder="Price" required>
</div>
</div>
<div class="form-group float-right">
<button type="submit" class="btn btn-success" [disabled]="!bookForm.valid">
<i class="bi bi-plus"></i>Update Book</button>
</div>
</form>
</div>
Angular firebase search
Many of my visitors are requesting me to make an Angular firebase search operation, I didn’t make it till now because I didn’t find any perfect search solution from @angular/fire/firestore. For some of my projects, I am using both @angular/fire/firestore and @angular/fire/compat/firestore. If you find any code that performs search queries using @angular/fire/firestore, please let me know and I’m also looking at it. Let’s perform an Angular firebase search using @angular/fire/compat/firestore. Here is our screenshot of the search operation.
What we are achieving?
- We are using rxjs combineLatest as an array of observables.
- We are performing OR search operation on three fields book names, genre, and authors using @angular/fire/compat/firestore.
- We need to import AngularFireModule from ‘@angular/fire/compat’.
Let first create searchComponent in the src/components folder and add search params and code for the search operation.
import { Component } from '@angular/core';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { combineLatest, map } from 'rxjs';
import { IBook } from 'src/app/models/book.model';
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss'],
})
export class SearchComponent {
books: IBook[] = [];
isSearchEmpty: boolean;
searchParams = {
name: null,
genre: null,
author: null,
};
constructor(private afsCompact: AngularFirestore) {}
onSearchBook() {
this.books = [];
const $name = this.afsCompact
.collection('books', (ref) =>
ref.where('name', '==', this.searchParams.name)
)
.valueChanges({ idField: 'id' });
const $genre = this.afsCompact
.collection('books', (ref) =>
ref.where('genre', '==', this.searchParams.genre)
)
.valueChanges({ idField: 'id' });
const $author = this.afsCompact
.collection('books', (ref) =>
ref.where('author', '>=', this.searchParams.author)
)
.valueChanges({ idField: 'id' });
combineLatest([$name, $genre, $author])
.pipe(map(([one, two, three]) => [...one, ...two, ...three]))
.subscribe((response: any) => {
this.books = response;
if (response.length > 0) {
} else {
this.isSearchEmpty = true;
}
});
}
}
Above is a simple example, if your result record depends on another collection, then you have to make an array of promises to retrieve the corresponding document from a collection.
Let’s add form in our search component template, let’s edit the src/components.search.component.html
<div class="container">
<section>
<h4>Search firbase record</h4>
<div class="row grid-title">
<div class="col-3 col-md-3">
<div class="form-group">
<label>Book Name</label>
<input
class="form-control"
name="name"
#name="ngModel"
[(ngModel)]="searchParams.name"
placeholder="Book Name"
required
/>
</div>
</div>
<div class="col-3 col-md-3">
<div class="form-group">
<label>Book Genre</label>
<input
class="form-control"
name="gener"
#gener="ngModel"
[(ngModel)]="searchParams.genre"
placeholder="Book Genre"
required
/>
</div>
</div>
<div class="col-3 col-md-3">
<div class="form-group">
<label>Book Author</label>
<input
class="form-control"
name="price"
#price="ngModel"
[(ngModel)]="searchParams.author"
placeholder="Book author"
required
/>
</div>
</div>
<div class="col-3 col-md-3">
<button class="btn btn-primary" (click)="onSearchBook()">Search</button>
</div>
</div>
</section>
<section *ngIf="books">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Author</th>
<th scope="col">Genres</th>
<th scope="col">Price</th>
</tr>
</thead>
<div *ngIf="!isSearchEmpty; else noSearch">
<tbody>
<tr *ngFor="let book of books; index as i">
<th scope="row">{{ i + 1 }}</th>
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.genre }}</td>
<td>{{ book.price }}</td>
</tr>
</tbody>
</div>
</table>
<ng-template #noSearch> Search result not found ! </ng-template>
</section>
</div>
At last, we need to import
....
import { AngularFireModule } from '@angular/fire/compat';
@NgModule({
declarations: [
...
imports: [
BrowserModule,
...
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideFirestore(() => getFirestore()),
provideAuth(() => getAuth()),
AngularFireModule.initializeApp(environment.firebase),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Conclusion: Now we had completed the Angular Firestore CRUD operation, as this tutorial becomes lengthy, we had covered the Angular Firestore query and search operation. I hope you got some idea, of how to use AngularFire latest and I had uploaded above example in Github.com
Related Post
- How to implement Angular material form in Angular 11 | 12?
- How to implement angular reactive forms validation in Angular 12 .?
hey you didn’t show search example
Sorry, I thought to add, but the tutorial became lengthy. So I thought to create separate articles for a search query, sort, and pagination.
Error: src/app/components/home/home.component.html:4:13 – error NG8001: ‘app-book’ is not a known element:
1. If ‘app-book’ is an Angular component, then verify that it is part of this module.
2. If ‘app-book’ is a Web Component then add ‘CUSTOM_ELEMENTS_SCHEMA’ to the ‘@NgModule.schemas’ of this component to suppress this message.
facing this error..kindly guide
How do you use the ‘orderby’ showing the whole list?
Hi. Do you have the same example with realtime database?
thnks.
Hey, where did you find the documentation which you based this tutorial on? I’m not finding the documentation on the github repo good at all! :O
Thanks a lot!!! This has been really helpful for me. It is one of the few resources on the net that deal with AngularFire 7. I checked today (4th, feb, 2022) and they still have not posted new docs for this version. I would really appreciate if they provided better docs (given it is official Google). I am new to Firebase so I need detailed instructions. If you know about any other great resources on AngularFire 7 (and 6 as well), please drop a link. Keep the good work!
Muchas gracias por el tutorial bien explicado, no hay mucha documentación con fire 7.2
por favor si nos puedes pasar solo el método service de la búsqueda.
Lo revise 14 de febrero 2022
thxsss
Came here for the search example.
Would be great if you could add search.
I had just added code for search using AngularFireModule.
Love this. Clarified a lot. But where the part 2 of this at? 4
please i need the link to the source code
I thought, I had upload in my github repositories. Sorry, I will upload to Github, please check conclusion section, where i add Github link of Angularfire, if it helps you.
how do you
orderBy(‘dateToday’, ‘desc’).limit(1) with AngularFire v7?
I need to retrieve a collection, order by serverTimestamp descending and limit to 1 or sometimes 78.
How is this done with AngularFire 7 ?
Hi Frank, sorry for the late reply, as I’m busy with React project. I guess this will help you.
import {
Firestore,
collection,
collectionData,
query,
orderBy,
limit,
…
} from ‘@angular/fire/firestore’;
…
constructor(private firestore: Firestore ) {}
someMethod() {
const ref = collection(this.firestore, ‘books’);
const q = query(ref, orderBy(‘name’), limit(2));
return collectionData(q);
}
you have to subscribe someMethod
Once thing I noticed if I try to subscribe to an Observable that is returned from collectionData(q) and execute some code in the ‘complete’ function it never seems to complete or error out. Is there a reason for this?
Thanks a lot. It is really helpful.
Great thread 🙂
If I inject private firestore: Firestore into my service I get an error “Error: Uncaught (in promise): FirebaseError: Firebase: Need to provide options, when not being deployed to hosting via source. (app/no-options).”.
This is strange as I’m using Firebase authentication and it works fine!
Any ideas?