Skip to content
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

ES6: No provider for NavController! (MyApp -> NavController) #5543

Closed
nraboy opened this issue Feb 21, 2016 · 14 comments
Closed

ES6: No provider for NavController! (MyApp -> NavController) #5543

nraboy opened this issue Feb 21, 2016 · 14 comments
Assignees
Milestone

Comments

@nraboy
Copy link

nraboy commented Feb 21, 2016

Short description of the problem:

NavController not injecting in the latest beta.

What behavior are you expecting?

NavController to inject in the constructor method

Steps to reproduce:

ionic start ExampleProject blank --v2
cd ExampleProject
ionic platform add android
ionic platform add ios

In the app/app.js file add the following code:

import {App, Platform, NavController, Alert} from 'ionic-framework/ionic';
import {Inject} from 'angular2/core';
import {HomePage} from './pages/home/home';


@App({
    template: '<ion-nav [root]="rootPage"></ion-nav>',
    config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
    constructor(@Inject(Platform) platform, @Inject(NavController) navController) {
        this.rootPage = HomePage;

        platform.ready().then(() => {

        });
    }
}

Ionic Version: 2.x

Run ionic info from terminal/cmd prompt:

Cordova CLI: 6.0.0
Gulp version:  CLI version 3.9.1
Gulp local:  
Ionic Version: 2.0.0-beta.1
Ionic CLI Version: 2.0.0-beta.17
Ionic App Lib Version: 2.0.0-beta.8
ios-deploy version: Not installed
ios-sim version: 5.0.6 
OS: Mac OS X El Capitan
Node Version: v0.12.7
Xcode version: Xcode 7.2.1 Build version 7C1002 
@tlancina
Copy link
Contributor

This is intended behavior, as weird as it seems at first. Nav here is a child of MyApp, (specifically a ViewChild, because it's in MyApp's template), which means there is no NavController injector available to MyApp.

You can use @ViewChild to access Nav specifically (which extends NavController):

import {App, Platform, NavController, Alert} from 'ionic-framework/ionic';
import {Inject, ViewChild} from 'angular2/core';
import {HomePage} from './pages/home/home';
import {SomeOtherPage} from './pages/someotherpage/someotherpage';

@App({
    template: '<ion-nav [root]="rootPage"></ion-nav>',
    config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
    @ViewChild(Nav) nav;

    constructor(@Inject(Platform) platform) {
        this.rootPage = HomePage;

        platform.ready().then(() => {

        });
    }

    ngAfterViewInit(){
      //this.nav is now defined
      setTimeout(() => {
        this.nav.push(SomeOtherPage);
      }, 2000);
    }
}

I'm not sure if there's a more Javascript-y way to use ViewChild, as I'm pretty sure the above is TypeScript, but all of the starters use the TypeScript compiler so it will work just fine either way (for more discussion on that see: #5493).

Going to close this as it's not a bug, but please feel free to comment if you have any other questions/issues, thanks!

@nraboy
Copy link
Author

nraboy commented Feb 21, 2016

This seems kind of sketch. What if you just throw a more identifiable exception when someone tries to do this in the @app file.

@seanwarner
Copy link

@nraboy If I understand @tlancina correctly, this issue is unrelated to @app, but is instead an issue strictly because the NavController is a child of this particular component. If you had done this in an @component or @page you would wind up with the same problem.

I definitely feel that the error reported is vague as it seems to be a problem with available providers rather than the instantiation context. An error indicating the trouble is as a result of attempting to access a ViewChild through injection would be considerably more helpful.

While I think the intuitive approach for attempting to access this component is through injection, the ViewChild decorator seems to be in line with Angular2's design approach and is reasonably well documented by Angular2 here. Currently I believe the most useful thing that could be done to handle these sorts of issues would be to provide better documentation, especially regarding the Nav Controller. Several recent issues posted on the Ionic Forums seem to be related to the subject, which implies a lack of understanding by the community for this feature.

@nraboy
Copy link
Author

nraboy commented Mar 2, 2016

+1 on documentation

@zhouhao27
Copy link

I got the error message:

Missing class properties transform.

at @ViewChild(Nav) nav;

@apyadav10
Copy link

I think in app.js, you can just do the following to get a handle to the NavController, where this.app is reference to App
let nav = this.app.getComponent('nav');

@tlancina
Copy link
Contributor

tlancina commented Mar 7, 2016

Thanks for the feedback everyone, this was not a well documented case, so I've updated the docs on using getComponent to get a reference to a child Nav (vs using @ViewChild) from the root component: http://ionicframework.com/docs/v2/components/#navigating_from_root.

When I originally answered I thought getComponent had been deprecated, but it was only for getting a hold of Menu references, which you now do with MenuController. I'm not sure what the roadmap is, but I believe there was some discussion of having a MenuController-like service at some point for managing NavControllers that would be available from the root component as well.

@Tomino2112
Copy link

@ViewChild(Nav) nav;

Should be somewhere in big bold red letters. Hours of googling finally did some good

@luckyforu
Copy link

luckyforu commented May 11, 2016

Scenario - I have implemented push notifications in ionic2.

On getting notification and clicking on it, i want to redirect to different pages based on the additional data that comes from the server.
I want to move this logic to a separate ts file and and enable push notification by calling init method of the new file created which contains all the code in the root component.

I tried writing a separate component with @page decorator with no template in it.
But since i need NavController for navigating to different pages i injected NavController but i always get No Provider error for my component. What am i doing wrong, any pointers?

`import {Injectable} from 'angular2/core';
import {Push} from 'ionic-native';
import {Page, NavController, NavParams} from 'ionic-angular';
import { ROUTER_DIRECTIVES } from 'angular2/router';
import {DeviceService} from './device/device.service';
import {LunchService} from './lunch/lunch.service';
import {LunchDetail} from './lunch/lunchDetail';

export interface NotificationEventResponse extends PhonegapPluginPush.NotificationEventResponse {
    additionalData: NotificationEventAdditionalData;
}

export interface NotificationEventAdditionalData extends PhonegapPluginPush.NotificationEventAdditionalData {
    additionalData?: any;
}

@Page({
    templateUrl: '',
    providers: [LunchService, DeviceService],
    directives: [ROUTER_DIRECTIVES]
})

//@Injectable()
export class MyPush{
    lunchDetails:any;
    nav: NavController;
    navParams: NavParams;

    constructor(nav:NavController, private _lunchService: LunchService, private _deviceService:DeviceService){
        console.log(this.nav);
        console.log(this._deviceService);
        console.log(this._lunchService);
    }

    push = Push.init({
        android: {
            senderID: "XXXXXXXXXXX"
        },
        ios: {
            alert: "true",
            badge: true,
            sound: 'false'
        },
        windows: {}
    });

    enablePush(){
        console.log()
        this.push.on('registration', (data) => {
            console.log(data.registrationId);
            this._deviceService.setDeviceId(data.registrationId);
            this._deviceService.saveDeviceId(data.registrationId)
            .subscribe(
                data => {},
                error => {}
            );
        });

        this.push.on('notification', (data:NotificationEventResponse) => {
            if(data.additionalData.additionalData.type == "lunch"){
                this._lunchService.setCachedData(data.additionalData.additionalData.lunch);
                //Key functionality
                this.nav.push(LunchDetail,{finalDate:null});
                alert("Hi, Am a lunch push notification");
            } else if (data.additionalData.additionalData.type == "snack"){
                alert("Hi, Am a snack push notification");
            } else{
                alert("This is a generic push");
            }
        });

        this.push.on('error', (e) => {
            console.log(e.message);
        });
    }
}
  `

@gillestasse
Copy link

I made it work using :
this.app._rootNav.setRoot(pageComponent);

@brb-elia
Copy link

Here is where I found the solution.

@bobrosoft
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);
  }

@kamil-kielczewski
Copy link

Here is solution to get nav controller in any provider

import {Injectable} from '@angular/core';
import {NavController, App} from "ionic-angular/index";
import { LoginPage } from "../../pages/login/login";
 
@Injectable()
export class ExampleProvider {
 
    private navCtrl: NavController;
 
    constructor(private app:App) {
        this.navCtrl = app.getActiveNav();
    }

    //...

    // example usage
    private Logout() {
        //...
        this.navCtrl.setRoot(LoginPage);
        this.navCtrl.popToRoot;
    }
}

I use this approach to detect unauthorized response from server in myAuthHttp which is Http wrapper (this wraper is used in all app instead standard Http and allow to send PUT/GET/POST/DELETE request with authentication token which expires after some time). But better solution will be to raise some 'event' from this provider and UI should detect it and go to login page - but how to do it?

@ionitron-bot
Copy link

ionitron-bot bot commented Sep 2, 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 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests