Ionic-framework: Ionic V2: No provider for NavController! Solution?

Created on 10 Dec 2016  ·  15Comments  ·  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")
[ ] 1.x
[x ] 2.x

I'm submitting a ... (check one with "x")
[ x] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/

Current behavior:
Injecting NavController in constructor of service fails with no provider error

Expected behavior:
to work

Steps to reproduce:
This class throws error (other dep. injection does not throw any error)

import {Interceptor, InterceptedRequest, InterceptedResponse} from 'ng2-interceptors';
import {NavController, Platform, AlertController} from "ionic-angular";
import {Injectable, Injector} from "@angular/core";

@Injectable()
export class ServerInterceptorService implements Interceptor {

  constructor(public platform: Platform,
              public alertCtl: AlertController,
              public navCtl: NavController) {
  }

  public interceptBefore(request: InterceptedRequest): InterceptedRequest {
    // Do whatever with request: get info or edit it

    return request;
    /*
     You can return:
     - Request: The modified request
     - Nothing: For convenience: It's just like returning the request
     - <any>(Observable.throw("cancelled")): Cancels the request, interrupting it from the pipeline, and calling back 'interceptAfter' in backwards order of those interceptors that got called up to this point.
     */
  }

  public interceptAfter(response: InterceptedResponse): InterceptedResponse {
    // Do whatever with response: get info or edit it
    console.log("////////////", response)
    return response;
    /*
     You can return:
     - Response: The modified response
     - Nothing: For convenience: It's just like returning the response
     */
  }
}

and the class above replaces http provider in app.module.ts

providers:[
    ServerInterceptorService,
    {
      provide: Http,
      useFactory: interceptorFactory,
      deps: [XHRBackend, RequestOptions, ServerInterceptorService]
    },
...]

Other dependencies are injected properly.

Most helpful comment

@m3l7 try next:

  constructor(
    protected app: App,
...
  get navCtrl(): NavController {
    return this.app.getRootNav();
  }

All 15 comments

According to https://forum.ionicframework.com/t/why-cant-i-import-navcontroller-and-viewcontroller-into-service-or-app/40999/26
its being said

Just to chime in on this, you shouldn't be injecting ViewController or NavController into Service.
This is not their intended purpose.

Then please tell me, how should we add global interceptors to the app, that would act depending on knowing what active view the user sees?

Shall we overcomplicate our lives by telling each view component to listen to or subscribe to the interceptor service if it emits something depending on its internal logic so the view would know if it should go back to the login page?

according to
https://medium.com/coding-snippets/ionic-2-ui-alert-from-a-angular-2-service-221a2e526760#.spxbdpfz1

constructor(private app: IonicApp) {}
let alert = Alert.create({title: 'Error', message: message, buttons: ['OK']});
var nav = this.app.getActiveNav();
nav.present(alert

does not work in rc3 for me.

I'm might be missing some point but...

Just because Angular team or others says that _this is a view component and that is a service object_, totally isolating them just because of some kind of categorizing fixation does not help. All of them are objects that could and should be able to get a reference to each other when needed.

Moreover NavController on an abstract application level is more an orchestrating global controller than a simple view coupled class. So since NavController is "so core" I would suggest rethinking this design or adding a centralized app wide service to the Ionic core module.

There is a very simple dirty workaround, within your app.component.ts the marvellous
@ViewChild('carguardNav') navCtrl: NavController
can be passed to other service providers like

myGlobalService.nav = this.navCtrl

during platform initialization phase, and then can be retrieved from your other service that depends on and had injected MyGlobalService.

Hello! Sorry that your having issues here. So NavController cannot be injected into a service because a service does not have a NavController. This means that the Angular dependency injection does not know which NavController to get a reference too causing an error. An important thing to remember is that this is not central to our NavController, it is a standard Angular DI error. If i'm understanding your use case correctly, you could use event emitters to get the same functionality. Because this is not an error on our part, but simply how Dependency Injection works in Angular 2 I am going to close this issue for now, but i would strongly recommend that you open a feature request for the centralized app wide navcontroller service idea that you mention above. Thanks for using Ionic!

Actually I have made another solution for whom might concern, I am using app wide events to connect view and service components through IoC pattern meaning the good old broadcasting events from services and subscribing to them in view components.

@barocsi Do you mind posting your solution? I am running into the same problem.

Forced that shit to work with getter and Injector

  constructor(
    protected injector: Injector
  ) {

...

  get navCtrl(): NavController {
    return this.injector.get(NavController);
  }

@bobrosoft do you have a working example? I get "no injector for Navcontroller" again with your code

@m3l7 try next:

  constructor(
    protected app: App,
...
  get navCtrl(): NavController {
    return this.app.getRootNav();
  }

@bobrosoft ok, it works.. the problem is that by calling directly nav.push(MyComponent) I get a loop of dependencies, so I'm force to use events caught by a "router" service which will trigger the nav.push (hoping that this solution will work).

it would be great to have more advanced routing solutions in ionic2.. I'm just trying to make a basic 401 interceptor and redirect the app to the login page

Hey @bobrosoft : This is the way to it!

constructor(@Inject(Platform) platform, @Inject(NavController) navController) {
}

This is explained here: https://github.com/driftyco/ionic/issues/5543

@mpeguero that will not work if service (we about services, right?) instantiated on earlier stages and that's technically near the same as my first answer. I checked that before.

That solution

  constructor(
    protected app: App,
...
  get navCtrl(): NavController {
    return this.app.getRootNav();
  }

is better but not ideal too.

In the Ionic docs there is solution. It works fine.

Get Outlook for Androidhttp://aka.ms/ghei36

On Mon, Mar 20, 2017 at 4:44 AM -0400, "Vladimir Tolstikov" <[email protected]notifications@github.com> wrote:

@mpeguerohttps://github.com/mpeguero that will not work if service (we about services, right?) instantiated on earlier stages and that's technically near the same as my first answer. I checked that before.

That solution

constructor(
protected app: App,
...
get navCtrl(): NavController {
return this.app.getRootNav();
}

is better but not ideal too.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/driftyco/ionic/issues/9581#issuecomment-287701528, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ABvDpy-6mn19VUnkSbBakAj11hsdEv1zks5rnjxygaJpZM4LJvpd.

so what is the current solution on this matter? I try to open the Logout page if the Interceptor fetches an HttpErrorResponse status of 401 or 403, but can't get that to work. Seems impossible, really.

It's also common sense that a global service would not inject and instantiate a NavController. Assume you're in page A, whose component is using private navCtrl: NavController, and it's also using a global-function-provider.
Now if this provider is also injecting and using its own NavController, calling the provider from the component using it will mess things up.

In my opinion, whenever you want to use that Page's navCtrl, simply pass it as a parameter to the global function you're using.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings