Description
Hi,
thank you for the awesome library, especially the 5.0, it's forming to be the holy grail of angular apps with Firestore.
I need to use multiple projects with Angularfire, and currently it's not as developer friendly as it could be.
I request to have either
- Builtin support for bootstrapping and injecting multiple instances of the app, database, firestore, auth etc. or...
- Documentation level blueprint how to do it yourself
#1026 touches this issue a bit, but as far as I can see there is no final resolution.
As far as I can see the core Firebase library has support for this, and the Angularfire2 bootstrapping mechanism even takes the app id as parameter, but that is not really used anywhere and the different providers inject just the default app instance.
Option 1. could be implemented as one central service that would keep track of different FirebaseApps and have a map of those as well as different services (Database, Auth, Firestore etc.) that would be keyed by the app name.
AngularFireModule.initializeApp should be changed to take in multiple pairs of FirebaseAppConfig and appName. The first one would be the one that is used when using the normal, current injection. This way the backwards compatibility would be top notch.
The initialization logic would loop through the different configs, and set those to the central service and it's maps + return the same module definitions as the current implementation returns.
imports: [
AngularFireModule.initializeApp(environment.myFirebaseConfig1, 'firebase1', environment.myFirebaseConfig2, 'firebase2')
]
This would enable us to use this in components or services:
...
export class LoginComponent implements OnInit, AfterContentChecked {
private auth1: AngularFireAuth
private auth2: AngularFireAuth
constructor(
private auth: AngularFireAuth, //This would be the default, configured using myFirebaseConfig1 above
private angularFireService: AngularFireService //New service, containing all confs and related services
) {
this.auth1 = auth
this.auth2 = angularFireService.getAuth('firebase2') //the same id as given in initializeApp call above
}
...
This is also forward compatible if Angular ever supports more sophisticated injection methods.(somekind of markers or other ways to allow injection of different instances of the same class)
Option 2. would be simply documenting something along these lines:
app.module.ts:
import { MyAngularFireAuth, MyAngularFireDatabase, MyAngularFirestore, MyFirebaseApp, _firebaseAppFactory } from './angularfire.extensions'
@NgModule({
...
providers: [
{ provide: MyFirebaseApp, useValue: _firebaseAppFactory(environment.myOtherFirebaseConfig, 'myFirebase') },
{ provide: MyAngularFirestore, deps: [MyFirebaseApp], useFactory:
(myFirebaseApp: MyFirebaseApp): MyAngularFirestore => {
return new MyAngularFirestore(myFirebaseApp, true)
}
},
{ provide: MyAngularFireAuth, deps: [MyFirebaseApp], useFactory:
(myFirebaseApp: MyFirebaseApp): MyAngularFireAuth => {
return new MyAngularFireAuth(myFirebaseApp)
}
},
{ provide: MyAngularFireDatabase, deps: [MyFirebaseApp], useFactory:
(myFirebaseApp: MyFirebaseApp): MyAngularFireDatabase => {
return new MyAngularFireDatabase(myFirebaseApp)
}
}
]
...
})
export class AppModule { }
angularfire.extensions.ts:
import { FirebaseApp, FirebaseAppConfig } from 'angularfire2'
import { AngularFireAuth } from 'angularfire2/auth'
import { AngularFireDatabase } from 'angularfire2/database'
import { AngularFirestore } from 'angularfire2/firestore'
import * as firebase from 'firebase'
export function _firebaseAppFactory(config: FirebaseAppConfig, appName?: string): FirebaseApp {
try {
if (appName) {
return firebase.initializeApp(config, appName) as FirebaseApp;
} else {
return firebase.initializeApp(config) as FirebaseApp;
}
}
catch (e) {
if (e.code === "app/duplicate-app") {
return firebase.app(e.name) as FirebaseApp;
}
return firebase.app(null!) as FirebaseApp;
}
}
export class MyAngularFireAuth extends AngularFireAuth {
}
export class MyFirebaseApp extends FirebaseApp {
}
export class MyAngularFireDatabase extends AngularFireDatabase {
}
export class MyAngularFirestore extends AngularFirestore {
}
The above code has been briefly tested and found working.
Obviously regardless which option is chosen, it is required that the underlying code does not make assumptions that there is only one instance of any given class out in the wild. As far as I've red the code we're safe here.