angular-firestype v9.3.1
AngularFirestype
Type handling for AngularFirestore
This module extends AngularFirestore with type handling. Using a mapping object, it can add custom objects and get instancied data from Firestore without additional steps.
Install
npm i angular-firestype --saveUse
Module initialization
Import the module in your app after AngularFireModule :
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestypeModule, ValueType } from 'angular-firestype';
import { environment } from '../environments/environment';
import { User } from './user.ts';
import { Address } from './address.ts';
import { Message } from './message.ts';
/**
* Definition of the app model mapping.
* For more information, see part #mapping-object below.
*/
const model: {[key: string]: ValueType<any>} = {
users: {
type: User,
arguments: ['username', 'picture'],
structure: {
adress: Address
},
subcollections: {
messages: Message
}
}
};
@NgModule({
imports: [
AngularFireModule.initializeApp(environment.firebase),
AngularFireAuthModule,
AngularFirestypeModule.forRoot(model), // Import module using forRoot() to add mapping information
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}model is a mapping object representing your app model organization.
AngularFirestypeModule should replace your AngularFirestoreModule if you have one imported.
Service injection and data manipulation
Then just inject service AngularFirestype and use it to get and set values to Firestore :
import { Component } from '@angular/core';
import { AngularFirestype, Collection, Document } from 'angular-firestype';
import { User } from './user.ts';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent {
const users: Observable<User[]>;
const user: User;
constructor(db: AngularFirestype) {
const usersCollection: Collection<User> = db.collection<User>('users');
usersCollection.valueChanges().subscribe(users => this.users = users);
const userDoc: Document<User> = usersCollection.document('user1');
userDoc.valueChanges().subscribe(user => this.user = user);
userDoc.set(this.user);
}
}AngularFirestype acts just as AngularFirestore but uses instances of custom objects defined in a provided model.
Model
In order for AngularFirestype to know how to transform your custom object to raw objects and instanciate them back from Firestore, you need to provide a mapping object containing data about your application model.
It is a map of ValueType, himself either a class for simple custom objects or a ValueDescriptor for more complex ones.
Here is an exemple of a model :
import { ValueType } from 'angular-firestype';
import { User } from './user.ts';
import { Address } from './address.ts';
import { Message } from './message.ts';
const model: {[key: string]: ValueType<any>} = { // {[key: string]: ValueType<any>} for TypeScript type check
messages: Message,
users: {
type: User,
arguments: ['username', 'picture'],
structure: {
address: Address
},
subcollections: {
messages: Message
},
options: {
timestampOnCreate: 'createdAt',
timestampOnUpdate: 'updatedAt'
}
}
};This model has two entries messages and users. They both represent a root collection in Firestore : /messages and /users.
messageswill be instances of classMessage, a simple custom class. A class is simple if it only contains basic types and no custom ones.usersis a more complex one and needs to be described as aValueDescriptor.ValueDescriptorhas the following attributes :type: class that will be instancied for this collection (Userfor theuserscollection). The constructor needs to be idempotent to work properly.arguments: array of arguments names to send to the constructor. If this attribute is defined, the constructor will be called with the values of the arguments names in order. For exemple, documents of the collectionuserswill be instancied this way :new User(valueOfUsername, valueOfPicture). If not defined, the constructor is called without arguments, likenew Message(). AngularFirestype only handle object's attributes as constructor arguments. Other ones need to be optional.structure: map ofValueType. This is the internal object description. AngularFirestype only needs to know about custom types and automatically handle basic types. In the case ofusers, thestructureattribute is saying that the classUserhas a custom typeAddressas attributeaddress. We could also have a complex custom type here and describe it like we did with the collectionusers, allowing nested custom types.elements:ValueTypedefining the custom type for elements contained in a collection. AValueDescriptorcan't have bothstructureandelementsdefined, as it represents either a custom object or a collection of custom objects.ignoreFields: Array of fields to ignore when performing a save in the database. Can also be an object containing arrays for set and/or update operations.subcollections: map ofValueType. Map of the collection subcollections and their corresponding custom types. Works the same asstructurebut for collections instead of objects. For example, collectionusershave a subcollectionmessages(/users/{userId}/messages in Firestore) of custom typeMessage. We could also have a complex custom type here and describe it like we did with the collectionusers, allowing nested subcollections.options: Additional options for thisValueDescriptor. Options implements interfaceValueOptions.
AngularFiretype add some model checking : you cannot add a document to a collection not defined in your model. If you try to do so, you'll get the following error: Value type not found for path: your/current/path
Differences with AngularFirestore
AngularFirestype presents a few differences with AngularFirestore :
- The module is initialized via
AngularFirestypeModule.forRoot(model): This is used to pass the model to AngularFirestype. If you need offline persistance, callAngularFirestypeModule.forRoot(model, true)instead. - You cannot add a document to a collection not defined in AngularFiretype's model mapping.
Collection,CollectionGroupandDocumentreplaceAngularFirestoreCollection,AngularFirestoreCollectionGroupandAngularFirestoreDocument. They work with custom types, inferred from the collection path and the provided model.CollectionandCollectionGroupqueries should be built using operator chaining like in firebase firestore. Here is an exemple :db.collection('items').where('size', '==', 'large').DocumentSnapshot,DocumentChange,DocumentChangeAction, andQuerySnapShothave been redefined to work with custom types.DocumentSnapshothas a newvalueproperty with the instancied custom object, anddocumentto get theDocumentreference.QuerySnapShothave similar properties withvaluesanddocuments.- There is multiple utility functions in
Document,CollectionandCollectionGrouplikedocumentChanges()allowing to access your data more easily.
Contribution
Any contribution is appreciated : simply use AngularFirestype, talk about it, give some feedback or even develop something. And if you feel like it, you can support me through Paypal :
In all cases, thank you for your interest in AngularFirestype !
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
