APP_INITIALIZER raises “Cannot instantiate cyclic dependency! ApplicationRef_” when used with a custom Http provider that is redirecting

佐手、 提交于 2019-11-28 17:44:14

The problem is that Router can async load some routes. This is why it needs Http. Your Http depends on Router and Router depends on Http. Angular injector is not able to create any of these services.

I had similar problems and one of the solutions can be injecting Injector instead of service and getting service afterwards.

Code:

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions,
    private injector: Injector, private dataHelper: DataHelperService) {
    super(backend, defaultOptions);
  }

  public get router(): Router { //this creates router property on your service.
     return this.injector.get(Router);
  }
  ...

So, basically, you do not need Router to get instance of Http service. The injection is done when you access router property - only when you want to redirect user. router property is transparent to other parts of code.

If it will not solve problem, you can do the same thing to the rest of injected services (except these to call super).

Maybe this helps; the way I solved this is by changing the strategy for the CustomHttp class to use composition instead.

My CustomHttp looks something like this:

@Injectable()
export class CustomHttp {

    constructor(private http: Http) {}

Now, I don't need Router nor any other service injected in my custom Http service.

In the configuration loader (config.service.ts) I made the following changes:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { AppSettings } from '../../environments/app-settings';
import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/toPromise';

@Injectable()
export class ConfigService {

  public settings:AppSettings;

  constructor() { }

  load(http: Http) : Promise<AppSettings> {
    let url = '/settings/';

    var observable= http.get(url)
            .map(res => res.json());

    observable.subscribe(config => this.settings = config);
    return observable.toPromise();
  }

}

Removed the need to inject the Http service dependency and instead added it to the load(http: Http) method.

In my app.module.ts I have the following:

providers: [
    {
        provide: Http,
        useFactory: (backend, options) => new CustomHttp(new Http(backend, options)),
        deps: [XHRBackend, RequestOptions]
    },
    ConfigService,
    {
        provide: APP_INITIALIZER,
        useFactory: (config, http) => () => config.load(http),
        deps: [ConfigService, Http],
        multi: true
    },

This is what I am currently using on my app. Not sure if this approach will work for you but hope it helps.

I solved it simply by removing Router from the deps declarations :

{
      provide: Http,
      useFactory: loadCustomHttp,
      deps: [XHRBackend, RequestOptions, DataHelperService]
    }

And everything else stay the same. It feels a bit like magic but it works.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!