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 --save
Use
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.
messages
will be instances of classMessage
, a simple custom class. A class is simple if it only contains basic types and no custom ones.users
is a more complex one and needs to be described as aValueDescriptor
.ValueDescriptor
has the following attributes :type
: class that will be instancied for this collection (User
for theusers
collection). 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 collectionusers
will 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
, thestructure
attribute is saying that the classUser
has a custom typeAddress
as attributeaddress
. We could also have a complex custom type here and describe it like we did with the collectionusers
, allowing nested custom types.elements
:ValueType
defining the custom type for elements contained in a collection. AValueDescriptor
can't have bothstructure
andelements
defined, 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 asstructure
but for collections instead of objects. For example, collectionusers
have 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
,CollectionGroup
andDocument
replaceAngularFirestoreCollection
,AngularFirestoreCollectionGroup
andAngularFirestoreDocument
. They work with custom types, inferred from the collection path and the provided model.Collection
andCollectionGroup
queries should be built using operator chaining like in firebase firestore. Here is an exemple :db.collection('items').where('size', '==', 'large')
.DocumentSnapshot
,DocumentChange
,DocumentChangeAction
, andQuerySnapShot
have been redefined to work with custom types.DocumentSnapshot
has a newvalue
property with the instancied custom object, anddocument
to get theDocument
reference.QuerySnapShot
have similar properties withvalues
anddocuments
.- There is multiple utility functions in
Document
,Collection
andCollectionGroup
likedocumentChanges()
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 !
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago