Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: add support for multiple firebase projects #1240

Closed
swftvsn opened this issue Oct 10, 2017 · 11 comments
Closed

Feature request: add support for multiple firebase projects #1240

swftvsn opened this issue Oct 10, 2017 · 11 comments

Comments

@swftvsn
Copy link

swftvsn commented Oct 10, 2017

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

  1. Builtin support for bootstrapping and injecting multiple instances of the app, database, firestore, auth etc. or...
  2. 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.

@swftvsn swftvsn changed the title Feature request: add support for multiple projects Feature request: add support for multiple firebase projects Oct 10, 2017
@jamesdaniels
Copy link
Member

jamesdaniels commented 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
Copy link
Author

swftvsn commented 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
Copy link

Hi @jamesdaniels, I'm not clear with your stackblitz.

In AppComponent, I see:
providers: [ { provide: FirebaseAppName, useValue: 'asdf' }, FirebaseAppProvider ]

But, in Console, the FirebaseApp seems not to use the value 'asdf' in providers.

image

I've tried to rename 2 apps in initializeApp() function of AppModule to any thing, it did not affect to the FirebaseApp.

And, when I switched the position of 2 initializeApp() functions, I saw the changing of the FirebaseApp. I think it always use the last initialized app.

Please help, thanks.

@magleahy
Copy link

magleahy commented 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'),

@ghost
Copy link

ghost commented Oct 23, 2017

hi,
same problem,
can someone help me to find the solution ?
thanks you

@swftvsn
Copy link
Author

swftvsn commented 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
Copy link

You could take a look at the solution I am using here.
Hope it helps :)

@jakeleveroni
Copy link

@jamesdaniels example works for swapping the FirebaseApp object between configurations. But if you are relying on providers that inject providers like AngularFireAuth etc. They -- in this case AngularFireAuth object -- will use the configuration of the last initialized AngularFireModule in your app.module.ts.

It also seems like the FirebaseApp object does not expose the same methods that, for example, the AngularFireAuth module does. i.e. app.auth() does not contain an authState object (although it does have an onAuthStateChanged() callback). Is there a way to allow the other angularfire2 providers to swap easily between configurations as well?

@jamesdaniels
Copy link
Member

FYI angularfire2@next has a much much better solution.

@tamama
Copy link

tamama commented 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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants