Resolving circular dependencies caused by APP_INITIALIZER

My AuthenticationService is responsible for loading the AngularFirestore and is loaded in the RootComponent. All app modules are lazily loaded within the RootComponent (which contains the main router-outlet). However, several sub-modules also load the AngularFirestore.

I need to ensure that the AuthenticationService is initialized (which involves asynchronous operations) before any components or modules are loaded. To achieve this, I placed it in the APP_INITIALIZER provider. This approach leads to a cyclic-dependency error stating:

Cannot instantiate cyclic dependency! AngularFirestore
.

If I remove the AuthenticationService from the APP_INITIALIZER, the app functions without properly initializing the service.

Is there a solution to this issue? (other than manually calling auth.initialize() in all components)

App structure:

AppComponent -> RootComponent(AuthenticationService) -> All Submodules(AuthenticationService, AngularFirestore)
// AuthenticationService constructor
constructor(
    private auth : AngularFireAuth,
    private remoteconfig : AngularFireRemoteConfig,
    private keepalive: Keepalive,
    private idle: Idle, 
    private toast : ToastService,
    private router : Router,
    private fs : AngularFirestore,
    private http : HttpClient,
) 
// APP_INITIALIZER provider in app.module.ts
{
  provide: APP_INITIALIZER,
  multi: true,
  useFactory: authFactory,
  deps: [
    AuthenticationService
  ]
}
// Factory function for APP_INITIALIZER
export function authFactory(
  auth : AuthenticationService
) {
  return () : Promise<any> => auth.initialize();
}

Thank you!

Answer №1

After thoroughly reviewing numerous Github comments and unrelated Stack Overflow questions, I devised a solution that I stumbled upon while skimming through irrelevant issues in the Github comments section.

In summary: To avoid injection conflicts, create a new service specifically for AngularFirestore, either exclusively for the AuthenticationService or for the entire application. I opted for the latter approach.

Understanding the root of the problem:

Based on my understanding, the issue stems from my AuthenticationService loading AngularFirestore and incorporating it into its dependency tree. Consequently, any subsequent injection of AuthenticationService and AngularFirestore results in a cyclic dependency, where injecting AuthenticationService introduces AngularFirestore into the dependency tree, leading to duplicated injections of AngularFirestore when it is injected later. This results in an error. While there may be room for error in my interpretation, I believe this was the primary issue at hand.

Solving the dilemma:

Establish a separate service for importing AngularFirestore. By doing so, we remove it from the dependency tree and inject it as a service, thereby ensuring the safety of any subsequent injections of AngularFirestore.

// appfirestoreservice.ts
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})
export class AppFirestoreService {
  
  public fs : AngularFirestore;
  public readonly collection = this._fs.collection;
  public readonly doc = this._fs.doc;
  public readonly createId = this._fs.createId;

  constructor(
    private _fs : AngularFirestore,
  ) {
    this.fs = _fs;
  }
}
// App Initializer in AppModule
{
  provide: APP_INITIALIZER,
  multi: true,
  useFactory: initFactory,
  deps: [
    AppServiceInitializerService,
    RemoteConfigService,
    AuthenticationService,
  ]
},

In my scenario, I had to develop a service dedicated to loading both RemoteConfigService and AuthenticationService in sequential order due to their initialization requirements.

Best regards!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to automatically blur the input field and toggle it upon clicking the checkbox using Angular

<input (click)="check()" class="checkbox" type="checkbox"> <input [(ngModel)]="second_month" value="2019-09" type="month" [class.blurred]="isBlurred">> I need the second input(type=month) field to be initially blurred, and only unblur ...

How to format dates with month names in various languages using the date pipe

In my HTML code, I have set up the date display like this: <span >{{ item.lastModified | date : 'MMM d, y' }}</span> As a result, the displayed date looks something like Jul 20, 2021. However, when I switch my browser's language ...

NG0900: Issue encountered while attempting to compare '[object Object]'. Please note that only arrays and iterable objects are permitted for comparison

Experimenting with an Angular project where I am retrieving data from a Minecraft API and displaying it on my website. This is my first time working with Angular's HTTP requests. Encountered the following error code; NG0900: Error trying to diff &apo ...

Using selectors and mappers in Typescript generics

I am looking to create a versatile selector and mapper method. interface State { user: { name: string; age: number; } } const pickName = (state: State) => state.user.name; const selectAge = (state: State) => state.user.age; ...

Utilizing performance.now() in Angular SSR for enhanced performance on both client and server sides

In order to track the performance of my Angular components, I am looking to set up some performance metrics. While everything runs smoothly in "client mode", I encounter an issue when switching to SSR mode - the error message "performance" is undefined. I ...

Encountering an issue with Next.js, Typescript, and mongoose when attempting to use `let cached = global.mongoose

I attempted to create a cached mongoose connection for my Next.js + Typescript application, but the code I used was: let cached = global.mongoose; if (!cached) { cached = global.mongoose = { conn: null, promise: null }; } The use of global.mongoose res ...

Is there a way to retrieve the resolved data within the route definition in Angular?

I am looking to execute some actions within the route definition once the lazyloaded module is loaded. The route includes a resolver called UserDataResolverService. How can I retrieve and utilize the resolved data within the route definition? { ...

Angular applications hosted on .Net Core should include a robots.txt file to provide instructions to web

I am currently running a web application on a Windows server, built with Angular 5 for server side rendering and hosted within .Net Core. I recently uploaded a robots.txt file to the root directory of the server, but when attempting to access it via , the ...

Issue with Angular date field not displaying invalid input when form is submitted

I am encountering an issue with my simple form that contains only one date control. Whenever I input an invalid date like 30-Feb-2018, the control becomes invalid and my CSS style triggers a red border to indicate the error. The problem arises when the us ...

Developing and employing Services in Angular 2

Having some trouble with Angular2 as I explore it for the first time, specifically in creating and using a service. I've set up a data service like this: import {Injectable} from 'angular2/core'; import {recentActivity} from './app/com ...

Incorporating HTML code within a .ts file: a basic guide

I'm relatively new to Angular, but I've been given a project that's built with Angular. As I examine the .ts file containing the list of property types, I need to wrap a span around the label text. Is this doable? Here is the current list ...

What are the different ways to customize the appearance of embedded Power BI reports?

Recently, I developed a website that integrates PowerBI embedded features. For the mobile version of the site, I am working on adjusting the layout to center the reports with a margin-left style. Below are the configuration parameters I have set up: set ...

The name 'Landbot' cannot be located. Have you meant to type '_landbot' instead?

I'm currently in the process of integrating Landbot into my React.js application with TypeScript. I'm following this [doc] 1. However, I'm facing an issue where the code inside useEffect (new Landbot.Container) is causing an error. 'C ...

Ways to simulate an initialized class within a function without using dependency injection

Creating a unit test for a service that utilizes aws-sdk to retrieve all files from an s3 bucket poses a challenge. Within the function, the S3 class is instantiated and listObjectsV2 is used to fetch files from the bucket. For testing purposes, it's ...

The NgbTooltip fails to display the arrow icon ( ▼ ) within the NgbPopover's window

There appears to be an issue with the arrow div not functioning properly within NgpPopover body due to conflicting arrow classes for NgbPopover's div.arrow and NgbTooltip's div.arrow. This seems to be a known problem in ng-bootstrap when using bo ...

methods for array filtering in typescript

How do I filter an array in TypeScript? I attempted the following findAllPersonsNotVisited():Observable<Person[]> { var rightNow = new Date(); var res = rightNow.toISOString().slice(0,10).replace(/-/g,"-"); return this.db.list(& ...

Excluding a common attribute from a combined type of objects can lead to issues when accessing non-common attributes (TypeScript)

In the process of developing a wrapper function, I am passing a refs property into a send function. The Event type used to construct my state machine is defined as an intersection between a base interface { refs: NodeRefs } and a union of possible event ob ...

Performing a HTTP GET request in Angular 2 with custom headers

I recently came across some posts discussing how to set headers in a GET request. The code snippet below demonstrates one way to do this: let headers = new Headers({ 'Accept': 'application/json' }); headers.append('Authorization&a ...

Creating an HTTP method handler function in Next.js API routes with an unspecified number of generic parameters

Looking to create a wrapper function in NextJS for API routes that can handle multiple HTTP methods with different handlers. For example, check out the TS playground interface GetResponse { hello: string, } // empty object type PostResponse = Record&l ...

What is the best way to display noscript content within my Angular application?

What is the best way to show HTML content for users who do not have JavaScript enabled in my Angular application? Inserting the noscript tag directly into the index.html file does not seem to be effective. <body> <noscript>Test</noscrip ...