Simplify connection between Akita and Firebase inside an Angular project
Connect Firebase and Akita :
- Firestore Collection
- Firestore Document
- Firestore Collection Group
- Akita Array with Subcollections
- Authentication
- Storage
- Messaging
Schematics :
-
ng generate collection-service
-
ng generate subcollection-service
-
ng generate collection-guard
Create an Angular project:
ng new project-name
cd project-name
Add @angular/fire
:
ng add @angular/fire
Setup your environment with
AngularFirestoreModule
.
Add @datorama/akita
and akita-ng-fire
:
ng add @datorama/akita
? π Set up Akita's devtools? Y
? π Set up Akita's router store? Y <-- Required for subcollections
? βοΈ Set up Akita's Http Entity Service? No
? π₯ Set up Akita's Firebase Entity Service? Y <-- Install akita-ng-fire
First, create a new feature with Akita, and select "Firebase" :
ng g @datorama/akita:feature movies/movie
- Default
- Http
- Firebase <-- β
see more about akita schematics.
In your component you can now start listening on Firebase :
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let movie of movies$ | async">{{ movie.title }}</li>
</ul>
`
})
export class AppComponent implements OnInit {
public movies$: Observable<Movie[]>;
constructor(private service: MovieService, private query: MovieQuery) {}
ngOnInit() {
// Subscribe to the collection
this.service.syncCollection().subscribe();
// Get the list from the store
this.movies$ = this.query.selectAll();
}
}
The MovieService
should looks like that :
@Injectable({ providedIn: 'root' })
@CollectionConfig({ path: 'movies' })
export class MovieService extends CollectionService<MovieState> {
constructor(store: MovieStore) {
super(store);
}
}
RouterModule.forRoot()
akita-ng-fire
documentation can also be found in Akita's Documentation page.
Documentation for Collection can be found here :
- π Getting Started
- π§ββοΈ Collection Service API
- βοΈ Collection Service Configuration
- πββοΈ Collection Guard API
- βοΈ Collection Guard Configuration
- π Collection Group API
Documentation for Subcollection can be found here :
- Subcollection Service
- Custom Subcollection Service
- Composition of subcollection
Documentation to manage authentication can be found here :
Examples of what you can do with akita-ng-fire
You can subscribe to a specific document :
In Component :
ngOnInit() {
this.router.params.pipe(
switchMap(params => this.service.syncDoc({ id: params.id })),
takeUntil(this.destroyed$)
);
}
Or with the Guard :
@Injectable({ providedIn: 'root' })
export class MovieGuard extends CollectionGuard<Movie> {
constructor(service: MovieService) {
super(service);
}
// Override the default `sync` method
protected sync(next: ActivatedRouteSnapshot) {
return this.service.syncDoc({ id: next.params.id });
}
}
Let's take this example from Akita :
import { CollectionService, CollectionConfig, Query, syncQuery } from 'akita-ng-fire';
// A query that fetch all the articles with 5 comments
const articleQuery: Query<Article> = {
path: 'articles',
comments: (article: Article) => ({
path: `articles/${article.id}/comments`,
queryFn: (ref) => ref.limit(5)
})
}
@Injectable({ providedIn: 'root' })
@CollectionConfig({ path: 'articles' })
export class MoviesService extends CollectionService<MoviesState> {
// syncQuery needs to be bind to the service and takes a Query as second argument
syncQuery = syncQuery.bind(this, articleQuery);
constructor(store: MoviesStore) {
super(store);
}
}
Here we use
bind()
to link the syncQuery to the service. This design helps you to only import what you need.
To take advantage of types, add "strictBindCallApply": true
inside your tsconfig.json
file.
Now in Component:
ngOnInit() {
this.service.syncQuery()
.pipe(takeUntil(this.destroyed$))
.subscribe();
}
Or in the Guard :
@Injectable({ providedIn: 'root' })
export class MovieGuard extends CollectionGuard<Movie> {
// Note: Here service has to be protected to access syncQuery
constructor(protected service: MovieService) {
super(service);
}
// Override the default `sync` method
protected sync(next: ActivatedRouteSnapshot) {
return this.service.syncQuery();
}
}
Many thanks to :
- Netanel Basal for building, maintaining, and sharing his knowledge about Akita
- LoΓ―c Marie for all his feedbacks and contribution.
- Ariel Gueta for his great article about Akita and Firebase.