13

I know, this question may sound duplicate and I have tried everything found on stackover flow unable to resolve this problem, so please bear with me

To make you able to reproduce the error I am providing you the whole code thought this

Github Repo

Problem

I am getting the following error:

Provider parse errors:↵Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule in ./AppModule@-1:-1

enter image description here

Information about the scenario (Notes)

Note 1 File: response-interceptor.service.ts

Path: ./src/app/shared/interceptors/response-interceptor/

I am intercepting the HTTPClient responses to check the 401 error and when the error comes I need to ask user to re-login.

To show the re-login prompt to user I have made a global-functions-services that has a function 'relogin'

Note 2 File: global-function.service.ts

Path: ./src/app/shared/services/helper-services/global-function/

Here is the place where this all started to happen... As soon as I am injecting the PersonService

  constructor(
    public dialog: MatDialog,
    private _personService: PersonService
  ) { }

I am getting this error and in PersonService I cannot find any import that can cause the issue.

PersonService:
./src/app/shared/services/api-services/person/person.service.ts

import { IRequest } from './../../../interfaces/I-request';
import { environment } from 'environments/environment';
import { Injectable } from '@angular/core';

// for service
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/toPromise';

// models
import { Person } from 'app/shared/models/person';
import { RequestFactoryService, REQUEST_TYPES } from 'app/shared/factories/request-factory/request-factory.service';

@Injectable()
export class PersonService {
  private _requestService: IRequest;

  constructor(
    _requestFactoryService: RequestFactoryService
  ) {
    this._requestService = _requestFactoryService.getStorage(REQUEST_TYPES.HTTP);
  }

  public signup(record): Promise<Person> {
    let url = environment.api + 'person/public/signup';

    return this._requestService.post(url, record)  as Promise<Person>;;
  }

  public authenticate(code: string, password: string): Promise<Person> {
    let url = environment.api + 'auth/signin';

    let postData = {
      code: code,
      password: password
    }

    return this._requestService.post(url, postData) as Promise<Person>;
  }
}

Request

Please suggest a solution for this, I have already wasted 2 days to figure out the issue but no luck.

Many thanks!! in advance

Vikas Bansal
  • 10,662
  • 14
  • 58
  • 100

3 Answers3

9

Cyclic dependency, means circling around endless, like planets orbiting sun..

Solution: Break the dependency chain, Re-factor code.

You have GlobalFunctionService -> PersonService -> so on... -> ResponseInterceptorService -> and back to -> GlobalFunctionService.
Cycle complete.

REMOVE the PersonService dependency from GlobalFunctionService. (its not used anyway, if you need it then find different way to get around.)

      import { PersonService } from 'app/shared/services/api-services/person/person.service';
      import { Injectable } from '@angular/core';
      import { InputModalComponent } from 'app/shared/components/input-modal/input-modal.component';
      import { MatDialog } from '@angular/material';

      @Injectable()
      export class GlobalFunctionService {

        constructor(
          public dialog: MatDialog
        ) { }

        relogin(): void {
          let dialogRef = this.dialog.open(InputModalComponent, {
            width: '250px',
            data: { title: "Please provide your password to re-login." }
          });

          dialogRef.afterClosed().subscribe(result => {
            debugger
            console.log('The dialog was closed');
            let password = result;
          });
        }
      }
dipak
  • 2,011
  • 2
  • 17
  • 24
  • I need person service in global function service because I need to validate the user. Is there a way that you can suggeste to handle this? Many many thanks for your time brother. – Vikas Bansal Nov 03 '17 at 13:55
  • relogin(personService: PersonService) {..... }, Just avoid constructor. – dipak Nov 03 '17 at 13:56
  • in order to pass person service object in relogin function... i will have to inject person service into response interceptor service which again make the circular dependency. Please suggest something – Vikas Bansal Nov 03 '17 at 13:59
  • 1
    ah... Let me see – dipak Nov 03 '17 at 14:04
  • many thanks ... Many many thanks!! It's well said... `There’s no Government or Police on Stack-Overflow Perhaps there are a few Batmen and Supermen` – Vikas Bansal Nov 03 '17 at 14:06
  • I did briefly check the app, HttpInterceptor can not take any dependency which depends on HTTPClient( its like build me from me scenario..). Its interceptor. The solution would be to emit an event(EventEmitter, and subscribe it.) and show login dialog. will play around week end if i find time... Good week end!! – dipak Nov 03 '17 at 15:01
  • Many many thanks @codeChopper for your response and research. Is awful to know that it's not possible to inject a service that uses http client.... Happy weekend.. i will also try to find the best solution. As i am 5 days old to angular 4, I hardly know it's depth. – Vikas Bansal Nov 03 '17 at 17:21
  • 1
    see the diff, This is just a pointer to get you moving.... https://github.com/bansalvks/simpleAngular4App/compare/master...dvbava:master – dipak Nov 05 '17 at 20:47
  • thank you @CodeChopper thank you so much... this is more than enough. Sometimes I cannot believe my luck that I find people like you to save my world :D :) God bless!! – Vikas Bansal Nov 06 '17 at 05:30
5

Use setTimeout() function in constructor to assign service.

constructor(private injector: Injector) {
  setTimeout(() => {
      this.loginService = this.injector.get(LoginService);
  })
}

Try this and revert back if you face any issue.

Jayendra Bariya
  • 115
  • 1
  • 6
4

You have to modify your response-interceptor.service.ts

import { Injectable,Inject, Injector } from '@angular/core';

constructor( inj: Injector) { 
   this._globalFunctionService=inj.get(GlobalFunctionService)
 }

You can get more info From this link

jitender
  • 10,238
  • 1
  • 18
  • 44
  • I have already tried this and it did not work for me and gave `Maximum call stack size exceeded↵RangeError: Maximum call stack size exceeded` – Vikas Bansal Nov 03 '17 at 09:57
  • It works for your current problem now you have to look for the solution of `Maximum call stack` error instead – jitender Nov 03 '17 at 10:03
  • I don't think so because as you can see in [this plunker](https://plnkr.co/edit/8CpyAUSJcCiRqdZmuvt9?p=preview) solution is working fine – jitender Nov 03 '17 at 10:06
  • to ensure this you can simple skip `GlobalFunctionService` injection and comment line `this._globalFunctionService.relogin();` and then check if you get `maximum..` error – jitender Nov 03 '17 at 10:11
  • I did as you said and the app ran perfectly... @jitender so it seems the issue `Maximum call stack` due to the `cyclic dependency`... – Vikas Bansal Nov 03 '17 at 10:16