New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ionic V2: No provider for NavController! Solution? #9581

Closed
barocsi opened this Issue Dec 10, 2016 · 15 comments

Comments

Projects
None yet
8 participants
@barocsi
Copy link

barocsi commented Dec 10, 2016

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.

@barocsi barocsi closed this Dec 10, 2016

@barocsi barocsi reopened this Dec 10, 2016

@barocsi

This comment has been minimized.

Copy link
Author

barocsi commented Dec 10, 2016

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.

@barocsi barocsi changed the title Ionic V2: No provider for NavController! Ionic V2: No provider for NavController! Bad pattern? Dec 10, 2016

@barocsi

This comment has been minimized.

Copy link
Author

barocsi commented Dec 10, 2016

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.

@barocsi barocsi changed the title Ionic V2: No provider for NavController! Bad pattern? Ionic V2: No provider for NavController! Solution? Dec 10, 2016

@jgw96

This comment has been minimized.

Copy link
Contributor

jgw96 commented Dec 12, 2016

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!

@jgw96 jgw96 closed this Dec 12, 2016

@barocsi

This comment has been minimized.

Copy link
Author

barocsi commented Dec 15, 2016

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.

@gregfrasco

This comment has been minimized.

Copy link

gregfrasco commented Dec 22, 2016

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

@bobrosoft

This comment has been minimized.

Copy link

bobrosoft commented Feb 3, 2017

Forced that shit to work with getter and Injector

  constructor(
    protected injector: Injector
  ) {

...

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

This comment has been minimized.

Copy link

m3l7 commented Mar 9, 2017

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

@bobrosoft

This comment has been minimized.

Copy link

bobrosoft commented Mar 9, 2017

@m3l7 try next:

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

This comment has been minimized.

Copy link

m3l7 commented Mar 9, 2017

@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

@mpeguero

This comment has been minimized.

Copy link

mpeguero commented Mar 17, 2017

Hey @bobrosoft : This is the way to it!

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

This is explained here: #5543

@bobrosoft

This comment has been minimized.

Copy link

bobrosoft commented Mar 20, 2017

@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.

@mpeguero

This comment has been minimized.

Copy link

mpeguero commented Mar 22, 2017

@abaginski

This comment has been minimized.

Copy link

abaginski commented Mar 21, 2018

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.

@christopheelkhoury

This comment has been minimized.

Copy link

christopheelkhoury commented Jun 18, 2018

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.

@ionitron-bot

This comment has been minimized.

Copy link

ionitron-bot bot commented Sep 1, 2018

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.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 1, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.