{
"dependencies": {
"@angular/animations": "9.1.0",
"@angular/cdk": "^9.2.0",
"@angular/common": "9.1.0",
"@angular/compiler": "9.1.0",
"@angular/core": "9.1.0",
"@angular/fire": "^6.0.0-rc.1",
"@angular/forms": "9.1.0",
"@angular/material": "^9.2.0",
"@angular/platform-browser": "9.1.0",
"@angular/platform-browser-dynamic": "9.1.0",
"@angular/router": "9.1.0",
"@nrwl/angular": "9.1.4",
"core-js": "^2.5.4",
"firebase": "^7.8.0",
"moment": "^2.24.0",
"ngx-toastr": "^12.0.0",
"normalizr": "^3.6.0",
"rxjs": "~6.5.0",
"zone.js": "^0.10.2"
}
}
You may clone this repo (https://github.com/jahumes/angular-fire-error) and run/build the Angular app
Steps to set up and reproduce
Steps to reproduce the error:
npm run starthttp://localhost:4205/auth/loginsrc/app/auth/auth-routing.module.ts and replace the routes with the following code:const routes: Routes = [
{
path: 'login',
component: LoginComponent
},
{
path: 'logging-in',
component: LoggingInComponent
}
];
Sample data and security rules
<-- include/attach/link to some json sample data (or provide credentials to a sanitized, test Firebase project) -->
* Errors in the JavaScript console *
core.js:6185 ERROR Error: Cannot instantiate cyclic dependency! AngularFireAuth
at throwCyclicDependencyError (core.js:8035)
at R3Injector.hydrate (core.js:16861)
at R3Injector.get (core.js:16617)
at NgModuleRef$1.get (core.js:36024)
at Object.get (core.js:33773)
at getOrCreateInjectable (core.js:5805)
at Module.傻傻directiveInject (core.js:20861)
at NodeInjectorFactory.LoginComponent_Factory [as factory] (login.component.ts:11)
at getNodeInjectable (core.js:5950)
at instantiateRootComponent (core.js:12585)
* Output from firebase.database().enableLogging(true); *
* Screenshots *
No error in the console.
The Angular app appears to be working correctly. I am wondering if this is caused by the AuthGuards dynamically loading the firebase/auth module outside of Angular.
I have found a related issue. Please see (https://github.com/angular/angularfire/issues/2367)
I have spent some more time working on this and discovered that if you take the AngularFireAuthGuard that is provided by @angular/fire, you can fix this issue (and the related one) by removing to code that pushes the auth check outside of Angular (see https://github.com/jahumes/angular-fire-error/tree/guard-fix).
The change looks like:
constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined,
zone: NgZone,
private fireAuth: AngularFireAuth,
private router: Router
) {
// const auth = of(undefined).pipe(
// observeOn(new 傻AngularFireSchedulers(zone).outsideAngular),
// switchMap(() => zone.runOutsideAngular(() => import('firebase/auth'))),
// map(() => 傻firebaseAppFactory(options, zone, nameOrConfig)),
// map(app => app.auth()),
// shareReplay({bufferSize: 1, refCount: false}),
// );
// this.authState = auth.pipe(
// switchMap(auth => new Observable<User | null>(auth.onAuthStateChanged.bind(auth)))
// );
this.authState = this.fireAuth.authState;
}
Can you help me understand the purpose of importing the code from outside of Angular? I understand wanting to make the auth code import dynamic, but why does this need to run outside of Angular?
Below is an example of the code needed to make everything work as before but with lazy loading the firebase/auth module only when the auth guard is used (see https://github.com/jahumes/angular-fire-error/tree/guard-fix-with-lazy-loaded-firebase-auth)
constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined,
zone: NgZone,
// private fireAuth: AngularFireAuth,
private router: Router
) {
const auth = of(undefined).pipe(
// observeOn(new 傻AngularFireSchedulers(zone).outsideAngular),
switchMap(() => import('firebase/auth')),
map(() => 傻firebaseAppFactory(options, zone, nameOrConfig)),
map(app => app.auth()),
shareReplay({bufferSize: 1, refCount: false}),
);
this.authState = auth.pipe(
switchMap(auth => new Observable<User | null>(auth.onAuthStateChanged.bind(auth)))
);
// this.authState = this.fireAuth.authState;
}
I have reviewed this again, and it appears that the full fix for this would be (see ):
constructor(
@Inject(FIREBASE_OPTIONS) options: FirebaseOptions,
@Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined,
zone: NgZone,
private router: Router
) {
const auth = of(undefined).pipe(
observeOn(new 傻AngularFireSchedulers(zone).outsideAngular),
switchMap(() => zone.runOutsideAngular(() => import('firebase/auth'))),
observeOn(new 傻AngularFireSchedulers(zone).insideAngular),
map(() => 傻firebaseAppFactory(options, zone, nameOrConfig)),
map(app => app.auth()),
shareReplay({bufferSize: 1, refCount: false}),
);
this.authState = auth.pipe(
switchMap(auth => new Observable<User | null>(auth.onAuthStateChanged.bind(auth)))
);
}
We need to do it outside of Angular because loading firebase/auth has side effects. It loads @firebase/auth and then instantiates to auth library, which in turn creates timers and a bunch of other things we don鈥檛 want to be inside of Angular鈥檚 zone. I鈥檒l check on the PR but yeah my suspicion is that we鈥檙e coming back into Angular鈥檚 zone at the wrong time; if we need to come back into the Angular zone at all.
Thanks for the response. I think you are totally right. I believe that the issue comes when the firebaseAppFactory is called outside of Angular. On lazy loaded routes that are loaded on a full page refresh, I think the app is being instantiated before Angular is finished initializing when done outside of Zone.
This has been fixed in RC2.
I think it's not solved. I still have this error when using AuthGuard and lazy loaded modules
Error: Cannot instantiate cyclic dependency! AngularFireAuth
"dependencies": {
"@angular-material-extensions/password-strength": "^6.0.0",
"@angular/animations": "~9.1.3",
"@angular/cdk": "~9.1.2",
"@angular/common": "~9.1.3",
"@angular/compiler": "~9.1.3",
"@angular/core": "~9.1.3",
"@angular/fire": "^6.0.0",
"@angular/flex-layout": "^9.0.0-beta.29",
"@angular/forms": "~9.1.3",
"@angular/material": "~9.1.2",
"@angular/platform-browser": "~9.1.3",
"@angular/platform-browser-dynamic": "~9.1.3",
"@angular/router": "~9.1.3",
"@ng-select/ng-select": "^4.0.0",
"@ngx-formly/core": "^5.5.15",
"@ngx-formly/material": "^5.5.15",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "~4.0.0",
"firebase": "^7.8.1",
"ngx-auth-firebaseui": "^4.2.1",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
},
It happens when I reload a page or access to a page by the url. Not when I navigate to that page with the router.
I also face the exact same issue as @magoarcano
"dependencies": {
"@angular/animations": "^9.1.4",
"@angular/cdk": "^9.2.2",
"@angular/common": "^9.1.4",
"@angular/compiler": "^9.1.4",
"@angular/core": "^9.1.4",
"@angular/fire": "^6.0.0-rc.2",
"@angular/forms": "^9.1.4",
"@angular/platform-browser": "^9.1.4",
"@angular/platform-browser-dynamic": "^9.1.4",
"@angular/router": "^9.1.4",
"@angular/service-worker": "^9.1.4",
"@nebular/eva-icons": "^5.0.0",
"@nebular/theme": "^5.0.0",
"date-fns": "^2.12.0",
"eva-icons": "^1.1.3",
"firebase": "^7.14.2",
"ngx-date-fns": "^6.3.0",
"rxjs": "~6.5.5",
"tslib": "^1.11.1",
"zone.js": "~0.10.3"
}
Same issue. :(
Solved the issue by reordering the imports of modules.
In my case the error occurred because imports were as following: AngularFireAuthModule was after AngularFirstoreModule.
All you have to do is import AngularFireAuthModule before AngularFirestoreModule.
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@uloga Thank you very much! it was driving me crazy for more than one month.
But now, for the same circunstances I have this other error:
instrument.js:110 Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
I think it's related to this one somehow. It happens when I refresh the page, and then router.navigate to other page in the component.
Try creating your own redirect service and using it instead of router.navigate.
Service:
import { Injectable, NgZone } from '@angular/core';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class RedirectService {
constructor(
private zone: NgZone,
private router: Router
) { }
navigate(path: any[]){
return this.zone.run(() => {
this.router.navigate(path);
});
}
}
Use:
// import it in your file and constructor
constructor(
private redirect: RedirectService
){}
login(){
// login logic
this.redirect.navigate(['some_url_path']);
}
Thanks again! Since it's a problem caused by the Auth guards I just solved using the workaround provided here:
https://github.com/angular/angularfire/issues/2444#issue-611975138
Thanks for sharing, good to know in case I run in the same issue.
Most helpful comment
I also face the exact same issue as @magoarcano