0
votes

I am using Ionic 2 rc4.

I have an issue where I am getting an error due to a cyclical dependency.

  +-------------------------------------+
  |    LoginEmailPage    RegisterPage   |
  |           ↓           ↓↑            |
  |           UtilityService            |
  +-------------------------------------+

I have a class LoginEmailPage that makes use of UtilityService.

e.g. from LoginEmailPage:

this.utilityService.login(nav)

In UtilityService:

public login(nav: NavController): void {
    nav.popTo(RegisterPage);
}

RegisterPage also makes use of the utilityService, so I get an compile time error:

metadata_resolver.js:623Uncaught Error: Can't resolve all parameters for LoginEmailPage: (FirebaseAuth, MenuController,

NavController, NavParams, FormBuilder, ViewController, AlertController, PersonService, ?, Events, LoadingController). at CompileMetadataResolver._getDependenciesMetadata (http://localhost:8100/build/main.js:39298:19)

Where the ? is UtilityService.

Question

How can I have a service (UtilityService) navigate to a page (RegisterPage) that already references the service(UtilityService)?

Thanks

UPDATE

Due to advise below:

Based on this, I have tried using an Injector:

utilityService.ts

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

    private registerPage: RegisterPage = null;
    constructor(injector: Injector,...
        setTimeout(() => this.registerPage = injector.get(RegisterPage));

    public login(nav: NavController): void {
        nav.popTo(this.registerPage);
    }

But I still get the same error as above.

Second, I look at this and this, which suggests to make use of forwardRef. My problem is that my service is an @Injectable and not a @Component. So the examples I see, does something like:

@Component({
  selector: 'my-button',
  template: `<div>
               <icon></icon>
               <input type="button" />
             </div>`,
  directives: [forwardRef(() => MyIcon)] // MyIcon has not been defined yet
})                                       // forwardRef resolves as MyIcon when MyIcon is needed

Question

How can I get this to work with a service that is not a component, but rather an injectable?

UPDATE

Fore more information, I am adding the constructors of each file.

loginemail.ts

@Component({
    templateUrl: 'loginemail.html'
})

export class LoginEmailPage {
...
    constructor(public auth: FirebaseAuth, menu: MenuController, public nav: NavController, public navParams: NavParams, public builder: FormBuilder, public viewCtrl: ViewController, alertCtrl: AlertController, personService: PersonService, utilityService: UtilityService, events: Events, public loadingCtrl: LoadingController) {

register.ts

@Component({
    templateUrl: 'register.html'
})

export class RegisterPage {
...
    constructor(public nav: NavController, public navParams: NavParams, public builder: FormBuilder, personService: PersonService,
        public viewCtrl: ViewController, public alertCtrl: AlertController, utilityService: UtilityService, events: Events,
        public loadingCtrl: LoadingController, public auth: FirebaseAuth) {

utilityService.ts

@Injectable()
export class UtilityService {
...
    constructor(injector: Injector, alertCtrl: AlertController, menu: MenuController, popoverController: PopoverController, storage: Storage) {

UPDATE

Thanks to advise below, I try this.

utilityService.ts

import { Injectable, Inject, forwardRef } from "@angular/core";
import { RegisterPage } from '../register/register';

@Injectable()
export class UtilityService {
...

public registerPage: RegisterPage = null;

     constructor(@Inject(forwardRef(() => RegisterPage)) registerPage, ...
        this.registerPage = registerPage;
          ...
          nav.popTo(this.registerPage, { personModel });

But I still the original compile error. I must be doing something wrong. Any ideas?

UPDATE

In the RegisterPage, I use forwardRef:

constructor(@Inject(forwardRef(() => UtilityService)) utilityService

But I get the following error:

Error: No provider for RegisterPage!

So I add RegisterPage to the providers in app.modula.ts, but then I get:

Error: Uncaught (in promise): Error: Provider parse errors:
Cannot instantiate cyclic dependency! RegisterPage: in NgModule AppModule
Error: Provider parse errors:
Cannot instantiate cyclic dependency! RegisterPage: in NgModule AppModule
1
you could use forward reference angular.io/docs/ts/latest/cookbook/… - Suraj Rao
Thanks for you assistance, but I have tried an Injector and a forwardRef as you guys suggest, but cannot get either to work. I have UPDATED my explanation above to include more detail on this. If you can suggest anything, I would appreciate it. - Richard
forwardRef should not be necessary if each class is in its own file. Only if you need to reference classes further down in the same file forwardRef is required. - Günter Zöchbauer
I guess we need to see the constructors with parameters list of all involved service and component classes. - Günter Zöchbauer

1 Answers

1
votes

Try using forwardRef in the constructor of your component eg:

export class LoginEmailPage {
constructor(...
     @Inject(forwardRef(() => UtilityService))utilityService, events: Events,
        public loadingCtrl: LoadingController, public auth: FirebaseAuth) {

Check here

Also RegisterPage and LoginEmailPage are components not providers (injectable). It should not be set in constructor of UtilityService.