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

Unexpected Null Object Error in TypeScript Function

Hi there! I'm new to TypeScript and encountered an 'Object may be null' error in a function. The function is meant to add two LinkedLists together, each representing numbers (with each digit as its own node), and return a new LinkedList. Can ...

Dealing with API responses in Angular 2

Hello there! I am a beginner in Angular 2 and might ask some basic questions, so please bear with me. I am struggling to understand how to handle an API response. Below is my NodeJS Server API function (which has been checked and is working fine): router ...

Nesting two ngFor loops in Angular using the async pipe leads to consistent reloading of data

In my Angular application, I am trying to retrieve a list of parent elements and then for each parent, fetch its corresponding children (1 parent to n children). Parent Child1 Child2 Parent Child1 Parent3 Child1 Child2 Child3 Initially, I succes ...

Issue encountered in event.d.ts file at line 74, character 76: TypeScript error TS2370: A rest parameter is required to be an array type

I am currently working on a project in Angular 6 and I encountered an issue while trying to integrate Google Maps into my website. When running ng serve, I received the following errors: ERROR in node_modules/@types/googlemaps/reference/event.d.ts(74,76): ...

Exploring the JSON Array in Angular5 with the power of ngFor

Currently, I am working on a project using Angular5 and encountering an issue with the *ngFor directive. The model class I have defined looks like this: export class FetchApi { value: Array<String>; api_status: string; api_version: string; d ...

Step-by-step guide to setting up a TypeScript project on Ubuntu 15 using the

As a newcomer to UBUNTU, I have recently ventured into learning AngularJS2. However, when attempting to install typescript using the command: NPM install -g typescript I encountered the following error message: view image description here ...

Exploring AngularJS Service: simulating $rootElement and $rootScope for testing purposes

Currently, I am in the process of writing tests for a service responsible for updating meta information on a page. mod.service('MetaSrv', ['$rootScope', '$rootElement', function ($rootScope, $rootElement){ return { updat ...

Is it possible to modify the URL path between the ingress and service?

I have a docker image that is serving its server on / (root). In my ingress, I already have a service called homepage that corresponds to the /. My goal is: Visiting / should redirect me to the home page. Visiting /custom should lead me to the docker ser ...

When I utilize a component to create forms, the React component does not refresh itself

One of the components I am working with is a form handling component: import React, { useState } from "react"; export const useForm = (callback: any, initialState = {}) => { const [values, setValues] = useState(initialState); const onCha ...

What data structure is used to store HTML elements in TypeScript?

Currently, I am dealing with a typescript variable that holds the outcome of a query on the DOM: let games = document.getElementsByTagname("game"); My uncertainty lies in identifying the appropriate type for the resulting array. Should I expect an array ...

The bar chart functions perfectly on localhost but encounters issues after being hosted on Gitpage

Localhost Gitpage The bar chart was displaying correctly on localhost, but once it was hosted on Gitpage, it began to show issues. Any suggestions on how to resolve this? Repository Link: https://github.com/mzs21/bar-chart Live Preview: ...

String date in the format "dd-MM-yyyy" cannot be transformed into a date using the 'DatePipe' function

Having trouble with date conversion in my custom pipe. It seems that when using a locale of 'nl-nl' and trying to format the date as 'dd-MM-YYYY', I'm seeing an error message stating Unable to convert "16-02-2023" into a ...

Developing a calendar UI with similar features and functionality to Google Calendar using Ionic 2

My journey with Ionic 2 began only one week ago and has been relatively smooth sailing thus far. However, I have hit a roadblock - I need to create a calendar interface for users to book time slots. Can anyone offer assistance on how to tackle this task? ...

Testing the Snackbar function with Angular and TypeScript: Unit Testing

I've encountered an issue with a method called onDelete that utilizes a MatSnackBar which is injected in the constructor like so: constructor(private todoListService: TodolistService, private snackBar: MatSnackBar) { } onDelete(todoList: TodoList): v ...

Callback after completion of a for loop in Angular TypeScript

During the execution of my javascript async function, I encountered a situation where my printing code was running before the div creation. I needed to ensure that my print code would run only after the completion of the for loop, but I struggled to find a ...

When the JSON array is converted into a string, it appears as undefined

Below is a snippet of my service.spec.ts file: service.spec.ts it('should mock the http requests', inject([Service, MockBackend], (service, mockBackend) => { let result:any; mockBackend.connections.subscribe((connection) => { ...

In order to showcase the data from the second JSON by using the unique identifier

SCENARIO: I currently have two JSON files named contacts and workers: contacts [ { "name": "Jhon Doe", "gender": "Male", "workers": [ "e39f9302-77b3-4c52-a858-adb67651ce86", "38688c41-8fda-41d7-b0f5-c37dce3f5374" ] }, { "name": "Peter ...

What is the method for storing a JSON object path in a variable for use in a template?

Trying to fetch data from a lengthy path has proven challenging for me. I attempted to store the path in a variable and incorporate it into the template, but encountered some issues. Could someone assist me with this? Here is what I have tried: My store ...

Issue encountered: NPM error, unable to find solution for resolving dependency and addressing conflicting peer dependency

I am facing difficulties deploying my project on netlify due to NPM errors. Below are the dependencies: "dependencies": { "@angular/animations": "~15.1.1", ... (list of dependencies continues) ...

The error message states that the property "user" is not found in the type "Session & Partial<SessionData>"

I recently had a javascript code that I'm now attempting to convert into typescript route.get('/order', async(req,res) => { var sessionData = req.session; if(typeof sessionData.user === 'undefined') { ...