Repository navigation
Feature request: add support for multiple firebase projects #1240
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.
Activity
[-]Feature request: add support for multiple projects[/-][+]Feature request: add support for multiple firebase projects[/+]jamesdaniels commentedon Oct 14, 2017
This is already supported. Just initialize more than one Firebase app in your ngModule and then switch/swap/rename them via
providers.Here's a quick stackblitz demonstrating https://stackblitz.com/edit/angular-aw3pyc?file=app%2Fapp.component.ts
I'll add to the docs, in the meantime the DI docs for Angular are a good start. https://angular.io/guide/dependency-injection-in-action
swftvsn commentedon Oct 14, 2017
@jamesdaniels Thank you for the support! So I've missed a bit how Angular injection works.
Could you still show how to inject multiple instances of the same service to same component? The
stackblitz only shows how to inject one service. (It does let one choose which one to inject though.)
What do I do when I need all three in the same service?
nguyenluucuong commentedon Oct 17, 2017
Hi @jamesdaniels, I'm not clear with your stackblitz.
In
AppComponent, I see:providers: [ { provide: FirebaseAppName, useValue: 'asdf' }, FirebaseAppProvider ]But, in Console, the
FirebaseAppseems not to use the value 'asdf' inproviders.I've tried to rename 2 apps in
initializeApp()function ofAppModuleto any thing, it did not affect to theFirebaseApp.And, when I switched the position of 2
initializeApp()functions, I saw the changing of theFirebaseApp. I think it always use the last initialized app.Please help, thanks.
magleahy commentedon Oct 20, 2017
Also struggling to find how to implement 2 Firebase instances in the same project.
@nguyenluucuong as far as I can see - the second one is initialised when I try to initialise two in the app.module - imports e.g.
AngularFireModule.initializeApp(environment.firebaseConfig), AngularFireModule.initializeApp(environment.firebaseConfig2, 'second'),swftvsn commentedon Oct 24, 2017
@nguyenluucuong, @magleahy, @lemas-projetpos I've opened new issue #1305 to track the documentation of this, hopefully we'll then find out how to do it properly.
james11a commentedon Jan 31, 2018
You could take a look at the solution I am using here.
Hope it helps :)
jakeleveroni commentedon May 2, 2018
@jamesdaniels example works for swapping the
FirebaseAppobject between configurations. But if you are relying on providers that inject providers likeAngularFireAuthetc. They -- in this case AngularFireAuth object -- will use the configuration of the last initializedAngularFireModulein your app.module.ts.It also seems like the FirebaseApp object does not expose the same methods that, for example, the
AngularFireAuthmodule does. i.e.app.auth()does not contain anauthStateobject (although it does have anonAuthStateChanged()callback). Is there a way to allow the other angularfire2 providers to swap easily between configurations as well?jamesdaniels commentedon May 2, 2018
FYI
angularfire2@nexthas a much much better solution.tamama commentedon Aug 17, 2018
@jamesdaniels
Instead of initializing in app.module.ts, can I initialize dynamically?
At the time of compiliation, I do not know the coordinates of the firebase project, which I will only obtain after the client signs in.
I also need to delete the firebase coordinates as the user signs out.
Thanks in advance.
Kind regards,
Tamama
fbayanati commentedon Aug 20, 2018
Just to share as I was looking into multiple issues to find out something around Firestore, you may look into this stalkblitz, or the stackoverflow item in case.