NullInjectorError: No provider for InjectionToken angularfire2.app.options! 2021
Asked Answered
M

8

23

Okay I just started using angular firebase and I've been scratching my head for two days. Most of the tutorials out there are mostly for older versions of firebase

this is the error that I am receiving when I inject my authentication service to the component

Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[LoginService -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: 
  NullInjectorError: No provider for InjectionToken angularfire2.app.options!
NullInjectorError: R3InjectorError(AppModule)[LoginService -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: 
  NullInjectorError: No provider for InjectionToken angularfire2.app.options!

the following links haven't been helpful so far

Link1 Link2 Link3

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { LoginService } from 'src/services/login.service';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { LoginComponent } from './components/login/login.component';
import { HomeComponent } from './components/home/home.component';
import { NotFoundComponent } from './components/not-found/not-found.component';

import { environment } from '../environments/environment';

import { initializeApp,provideFirebaseApp } from '@angular/fire/app';
import { provideAuth,getAuth } from '@angular/fire/auth';
import { provideDatabase,getDatabase } from '@angular/fire/database';
import { provideFirestore,getFirestore } from '@angular/fire/firestore';
import { AngularFirestore } from '@angular/fire/compat/firestore';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    HomeComponent,
    NotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => getAuth()),
    provideDatabase(() => getDatabase()),
    provideFirestore(() => getFirestore()),
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [LoginService],
  bootstrap: [AppComponent]
})
export class AppModule { }

login.service.ts

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router';
import { AngularFirestore } from '@angular/fire/compat/firestore';


@Injectable({
  providedIn: 'root'
})
export class LoginService {
  userLoggedIn: boolean;  

  constructor(private afAuth: AngularFireAuth, private router : Router,  private afs: AngularFirestore) {
    this.userLoggedIn = false;
  }

  loginUser(email: string, password: string): Promise<any> {
      return this.afAuth.signInWithEmailAndPassword(email,password)
        .then(() => {
            console.log('Auth Service: loginUser: success');
             this.router.navigate(['']);
        })
        .catch(error => {
            console.log('Auth Service: login error...');
            console.log('error code', error.code);
            console.log('error', error);
            if (error.code)
                return { isValid: false, message: error.message };
            else
                return { isValid: false, message : "Login Error"}
        });
  }

}

login.component.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { LoginService } from 'src/services/login.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
  loginFormCtrl: FormGroup;

  constructor(private LoginService: LoginService, private router: Router) {
    this.loginFormCtrl = new FormGroup({
      email: new FormControl('', Validators.required),
      password: new FormControl(null, Validators.required)
    })
  }


  ngOnInit(): void {

  }

  onLogin() {
    if (this.loginFormCtrl.invalid)
      return;

    this.LoginService.loginUser(this.loginFormCtrl.value.email, this.loginFormCtrl.value.password).then((result) => {
      
      if (result == null) {                              
        console.log('logging in...');
        this.router.navigate(['']);             
      }
      else if (result.isValid == false) {
        console.log('login error', result);
      }
    });
  }

}

package.json

{
  "name": "fire-base",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~12.2.0",
    "@angular/common": "~12.2.0",
    "@angular/compiler": "~12.2.0",
    "@angular/core": "~12.2.0",
    "@angular/fire": "^7.1.1",
    "@angular/forms": "~12.2.0",
    "@angular/platform-browser": "~12.2.0",
    "@angular/platform-browser-dynamic": "~12.2.0",
    "@angular/router": "~12.2.0",
    "rxjs": "~6.6.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4",
    "firebase": "^9.1.0",
    "rxfire": "^6.0.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~12.2.7",
    "@angular/cli": "~12.2.7",
    "@angular/compiler-cli": "~12.2.0",
    "@types/jasmine": "~3.8.0",
    "@types/node": "^12.11.1",
    "jasmine-core": "~3.8.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "~1.7.0",
    "typescript": "~4.3.5"
  }
}
Misesteem answered 4/11, 2021 at 19:5 Comment(0)
P
33

The fix is actually really simple...

in your app.module.ts

import

import { FIREBASE_OPTIONS } from '@angular/fire/compat';

and then add this to the providers

providers: [
    { provide: FIREBASE_OPTIONS, useValue: environment.firebase }
],
Pigling answered 11/4, 2022 at 0:45 Comment(6)
It's very helpful!!Lavenialaver
esa si que es respuestaRearm
Any explanation as to why this works? Also, if trying to migrate away from the namespaced version of the lib, isn't this a problem since this is an import from the /compat directory?Thickwitted
I try this add provider in app.module.ts not work , I am working angular 17 version,Moresque
@Thickwitted I'm pretty sure it is. I haven't worked on an Angular project in a while, but I think it's better to move to the modular version of the library as I believe the migration to that is fully implemented.Pigling
@ArqamRafay try using the new modular implementation of the libraryPigling
N
18

It seems that AngularFire is in the middle of major changes that embrace Firebase's new modular API, but the documentation hasn't quite caught up. The gist is that the you are initializing the Firebase App using the new API, but trying to use Firebase resources with the old API.

The key is to look at the import statement. Compare old and new style of initializing the app:

import {AngularFireModule} from '@angular/fire/compat';

[...]

imports: [
    AngularFireModule.initializeApp(environment.firebase),
]

vs.

import {initializeApp, provideFirebaseApp} from '@angular/fire/app';

[...]

imports: [
    provideFirebaseApp( () => initializeApp(environment.firebase)),
]

Notice how the old style initialization is under the "compat" namespace. If you initialize your app this way, you must also use the compat libraries to access resources. For example, from the AngularFire docs:

import {AngularFirestore, AngularFirestoreDocument} from '@angular/fire/compat/firestore';

[...]

constructor(private afs: AngularFirestore) {
    this.itemDoc = afs.doc<Item>('items/1');
    this.item = this.itemDoc.valueChanges();
  }

However, this doesn't work with the new style app initialization. Instead you must use something like this, adapted from the Firebase docs:

import {doc, Firestore, getDoc} from '@angular/fire/firestore';

[...]

constructor(private firestore: Firestore) { }

[...]

const docRef = doc(this.firestore, "cities", "SF");
const docSnap = await getDoc(docRef);

Why does it matter? I assume, but do not know, that the instance of the app is not shared between old and new.

So, the moral of the story:

  • Most of the documentation on the internet uses the old API. If you want to use that API, use the "compat" version of the library.
  • If you want to use the modern modular API, make sure you're not using the "compat" library. And the best bet is to refer to the Firebase documentation until the AngularFire team has had a chance to catch up.
Norvall answered 3/1, 2022 at 3:23 Comment(1)
This is the best and most helpful solution.Overijssel
M
9

I had the same problem today and I agree: there's many versions and their documentation is disappointing.

The solution (in my case)

For my setup (angular 11 + angular/fire 6.1.5) i had to put the following in my app.module.ts file:

...
    imports: [
        ...
        AngularFireModule.initializeApp(environment.firebase),
    ],
...

(For me environment.firebase contains my firebase config.)

Further analysis of the problem below, you can stop reading if you don't care

The documentation for angular/fire 7 will tell you to do this:

provideFirebaseApp(() => initializeApp(environment.firebase)),

Which I'm sure works great for version 7, but angular 11 automatically installs version 6, because that's compatible.

Milline answered 5/11, 2021 at 9:50 Comment(2)
thanks !, I'll see if downgrading the angular version is of any helpMisesteem
Same error, same solution using Angular 13.1.1 and Fire 7.2.0 with the default skeleton initialization of AngularFire.Norvall
E
5

My issue was fixed when I used both versions of initialization

AngularFireModule.initializeApp(environment.firebase),
provideFirebaseApp(() => initializeApp(environment.firebase)),
Elwaine answered 20/1, 2022 at 4:25 Comment(1)
This defeats the purpose of v9 Firebase. Might as well drop the provideFirebaseAppSpinnaker
L
4

On the file app.module.ts add the following provider object:

import { FIREBASE_OPTIONS } from '@angular/fire/compat';
 @NgModule({
  providers: [
    { provide: FIREBASE_OPTIONS, useValue: environment.firebase }   
  ],
 })

taked from: [https://www.angularfix.com/2022/03/angular-fire-no-provider-for.html][1]

Lustrate answered 9/6, 2022 at 15:58 Comment(0)
Q
1

I have the same issue using auth-guard.

Fixed it by dropping the compat in the import path.

Before

import { hasCustomClaim, canActivate } from '@angular/fire/compat/auth-guard';

After

import { hasCustomClaim, canActivate } from '@angular/fire/auth-guard';
Quarles answered 7/6, 2022 at 17:0 Comment(0)
M
0

As advised by @Daniel Eisenhardt I downgraded my angular version. And it is now working ! Angular : ~11.2.4 and running ng add @angular/fire installed a compatible version of angular fire. ("^6.1.5") This is my updated file

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { NotFoundComponent } from './component/not-found/not-found.component';

import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireDatabaseModule } from '@angular/fire/database';
// import { AngularFireStorageModule } from '@angular/fire/storage';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    LoginComponent,
    NotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebase)
    AngularFirestoreModule,                                   
    AngularFireDatabaseModule,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }



package.json

{
  "name": "evnt-mgmnt-app",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~11.2.14",
    "@angular/common": "~11.2.14",
    "@angular/compiler": "~11.2.14",
    "@angular/core": "~11.2.14",
    "@angular/fire": "^6.1.5",
    "@angular/forms": "~11.2.14",
    "@angular/platform-browser": "~11.2.14",
    "@angular/platform-browser-dynamic": "~11.2.14",
    "@angular/router": "~11.2.14",
    "rxjs": "~6.6.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3",
    "firebase": "^7.0 || ^8.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1102.13",
    "@angular/cli": "~11.2.15",
    "@angular/compiler-cli": "~11.2.14",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.1.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "~1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~4.1.5",
    "@angular-devkit/architect": ">= 0.900 < 0.1300",
    "firebase-tools": "^8.0.0 || ^9.0.0",
    "fuzzy": "^0.1.3",
    "inquirer": "^6.2.2",
    "inquirer-autocomplete-prompt": "^1.0.1",
    "open": "^7.0.3",
    "jsonc-parser": "^3.0.0"
  }
}
Misesteem answered 5/11, 2021 at 14:56 Comment(0)
S
0

This error is likely a sign that you've not fully migrated to v9 Firebase.

v9 Firebase

Examples of v9 Firebase code https://dev.to/jdgamble555/angular-12-with-firebase-9-49a0

compat imports as an intermediate step

A simple first-step migration will require changing imports to compat versions.
This keeps code working but you'll not benefit from v9 tree-shaking.
The compat imports gives APIs compatible with v8 code BUT the provide methods e.g. provideFirebaseApp won't work until all imports are v9 imports i.e. back to not being compat imports.

So until ALL your relevant code is upgraded to v9 use the old way

import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { AngularFireAuthGuardModule } from '@angular/fire/compat/auth-guard';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    AngularFireModule.initializeApp(environment.firebase),
    AngularFirestoreModule,
    AngularFireAuthModule,
    AngularFireAuthGuardModule,
  ],
  ...
})
export class AppModule { }

Once your code is fully migrated go back to the provide methods:

import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
import { provideAuth, getAuth } from '@angular/fire/auth';
import { provideFirestore, getFirestore } from '@angular/fire/firestore';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    // firebase
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => getAuth()),
    provideFirestore(() => getFirestore()),

Spinnaker answered 23/5, 2022 at 13:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.