Angular Firebase Module boilerplate for AngularFire2 (using Firestore and Storage) NgModule
import { NgModule } from '@angular/core';
import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireStorageModule } from 'angularfire2/storage';
import { environment } from '../../environments/environment';
import { FirestoreService } from './firestore.service';
import { StorageService } from './storage.service';
@NgModule({
imports: [
AngularFireModule.initializeApp(environment.firebaseConfig, environment.firebaseId),
AngularFirestoreModule,
AngularFireAuthModule,
AngularFireStorageModule,
],
exports: [
AngularFireModule,
AngularFirestoreModule,
AngularFireAuthModule,
AngularFireStorageModule,
],
providers: [
FirestoreService, StorageService
]
})
export class FirebaseModule { }
import { Injectable } from '@angular/core';
import * as firebase from 'firebase/app';
import { AngularFirestore, AngularFirestoreDocument, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/switchMap';
type CollectionPredicate<T> = string | AngularFirestoreCollection<T>;
type DocPredicate<T> = string | AngularFirestoreDocument<T>;
@Injectable()
export class FirestoreService {
constructor(private afs: AngularFirestore) { }
/// **************
/// Get a Reference
/// **************
public col<T>(ref: CollectionPredicate<T>, queryFn?): AngularFirestoreCollection<T> {
return typeof ref === 'string' ? this.afs.collection<T>(ref, queryFn) : ref;
}
public doc<T>(ref: DocPredicate<T>): AngularFirestoreDocument<T> {
return typeof ref === 'string' ? this.afs.doc<T>(ref) : ref;
}
/// **************
/// Get Data
/// **************
public doc$<T>(ref: DocPredicate<T>): Observable<T> {
return this.doc(ref).snapshotChanges().map(doc => {
return doc.payload.data() as T
})
}
public col$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<T[]> {
return this.col(ref, queryFn).snapshotChanges().map(docs => {
return docs.map(a => a.payload.doc.data()) as T[]
});
}
/// with Ids
public colWithIds$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<any[]> {
return this.col(ref, queryFn).snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
});
});
}
/// **************
/// Write Data
/// **************
/// Firebase Server Timestamp
get timestamp() {
return firebase.firestore.FieldValue.serverTimestamp()
}
set<T>(ref: DocPredicate<T>, data: any) {
const timestamp = this.timestamp
return this.doc(ref).set({
...data,
updatedAt: timestamp,
createdAt: timestamp
})
}
update<T>(ref: DocPredicate<T>, data: any) {
return this.doc(ref).update({
...data,
updatedAt: this.timestamp
})
}
delete<T>(ref: DocPredicate<T>) {
return this.doc(ref).delete()
}
public add<T>(ref: CollectionPredicate<T>, data) {
const timestamp = this.timestamp
return this.col(ref).add({
...data,
updatedAt: timestamp,
createdAt: timestamp
})
}
geopoint(lat: number, lng: number) {
return new firebase.firestore.GeoPoint(lat, lng)
}
/// If doc exists update, otherwise set
upsert<T>(ref: DocPredicate<T>, data: any) {
const doc = this.doc(ref).snapshotChanges().take(1).toPromise()
return doc.then(snap => {
return snap.payload.exists ? this.update(ref, data) : this.set(ref, data)
})
}
/// **************
/// Inspect Data
/// **************
inspectDoc(ref: DocPredicate<any>): void {
const tick = new Date().getTime()
this.doc(ref).snapshotChanges()
.take(1)
.do(d => {
const tock = new Date().getTime() - tick
console.log(`Loaded Document in ${tock}ms`, d)
})
.subscribe()
}
inspectCol(ref: CollectionPredicate<any>): void {
const tick = new Date().getTime()
this.col(ref).snapshotChanges()
.take(1)
.do(c => {
const tock = new Date().getTime() - tick
console.log(`Loaded Collection in ${tock}ms`, c)
})
.subscribe()
}
/// **************
/// Create and read doc references
/// **************
/// create a reference between two documents
connect(host: DocPredicate<any>, key: string, doc: DocPredicate<any>) {
return this.doc(host).update({ [key]: this.doc(doc).ref })
}
/// returns a documents references mapped to AngularFirestoreDocument
docWithRefs$<T>(ref: DocPredicate<T>) {
return this.doc$(ref).map(doc => {
for (const k of Object.keys(doc)) {
if (doc[k] instanceof firebase.firestore.DocumentReference) {
doc[k] = this.doc(doc[k].path)
}
}
return doc
})
}
/// **************
/// Atomic batch example
/// **************
/// Just an example, you will need to customize this method.
atomic() {
const batch = firebase.firestore().batch()
/// add your operations here
const itemDoc = firebase.firestore().doc('items/myCoolItem');
const userDoc = firebase.firestore().doc('users/userId');
const currentTime = this.timestamp
batch.update(itemDoc, { timestamp: currentTime });
batch.update(userDoc, { timestamp: currentTime });
/// commit operations
return batch.commit()
}
}
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore } from 'angularfire2/firestore';
import { AngularFireStorage } from 'angularfire2/storage';
@Injectable()
export class StorageService {
constructor(public afAuth: AngularFireAuth, public afs: AngularFirestore, public afStore: AngularFireStorage) { }
// Uploads a file to the given path. End the path with an asterisk (*) to use the file's name.
// eg: uploadFile('myfiles/pictures/*', myFile)
uploadFile(path: string, fileObj: File) {
path = path && path.length > 0 && !path.endsWith('*') ? path : fileObj.name;
return this.afStore.ref(path).put(fileObj);
}
}