ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
50.89k stars 13.52k forks source link

bug: no provider for ionRouterOutlet #21630

Closed indraraj26 closed 4 years ago

indraraj26 commented 4 years ago

Bug Report

Ionic version:

[x] 5.x

Current behavior:

I have injected IonRouterOutlet to check canGoBack and getting this error

ERROR NullInjectorError: R3InjectorError(AppModule)[IonRouterOutlet -> IonRouterOutlet -> IonRouterOutlet]: 
  NullInjectorError: No provider for IonRouterOutlet!
    at NullInjector.get (http://localhost/vendor-es2015.js:37118:27)
    at R3Injector.get (http://localhost/vendor-es2015.js:51065:33)
    at R3Injector.get (http://localhost/vendor-es2015.js:51065:33)
    at R3Injector.get (http://localhost/vendor-es2015.js:51065:33)
    at NgModuleRef$1.get (http://localhost/vendor-es2015.js:68623:33)
    at Object.get (http://localhost/vendor-es2015.js:66351:35)
    at getOrCreateInjectable (http://localhost/vendor-es2015.js:40933:39)
    at ɵɵdirectiveInject (http://localhost/vendor-es2015.js:54999:12)
    at NodeInjectorFactory.AppComponent_Factory [as factory] (ng:///AppComponent/ɵfac.js:7:56)
    at getNodeInjectable (http://localhost/vendor-es2015.js:41078:44)

So i have added in app.module.ts of providers array but now getting this error

vendor-es2015.js:41302 ERROR Error: Cannot instantiate cyclic dependency! IonRouterOutlet
    at throwCyclicDependencyError (vendor-es2015.js:43122)
    at R3Injector.hydrate (vendor-es2015.js:51299)
    at R3Injector.get (vendor-es2015.js:51053)
    at NgModuleRef$1.get (vendor-es2015.js:68623)
    at Object.get (vendor-es2015.js:66351)
    at getOrCreateInjectable (vendor-es2015.js:40933)
    at Module.ɵɵdirectiveInject (vendor-es2015.js:54999)
    at Object.IonRouterOutlet_Factory [as factory] (vendor-es2015.js:104932)
    at R3Injector.hydrate (vendor-es2015.js:51303)
    at R3Injector.get (vendor-es2015.js:51053)

Expected behavior:

It should not through error

Steps to reproduce:

  1. go to app.component.ts and see in platform.isReady
  2. go to app.module.ts and see providers array

Related code:

Repository: https://github.com/indraraj26/ionic5-starter-tabs-sidemenu/tree/handle-back-button Branch: handle-back-button

this.platform.backButton.subscribeWithPriority(-1, async (_) => {
                console.log(
                    this._ionRouterOutlet.component,
                );
                if (!this._ionRouterOutlet.canGoBack()) {
                    await this._app.minimize();
                }
            });

Other information:

Ionic info:

ionic info

Ionic:

   Ionic CLI                     : 5.4.4 (C:\Users\indra26\AppData\Roaming\npm\node_modules\ionic)
   Ionic Framework               : @ionic/angular 5.1.0
   @angular-devkit/build-angular : 0.901.4
   @angular-devkit/schematics    : 9.1.4
   @angular/cli                  : 9.1.4
   @ionic/angular-toolkit        : 2.2.0

Cordova:

   Cordova CLI       : 9.0.0 (cordova-lib@9.0.1)
   Cordova Platforms : android 8.1.0
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.2.1, (and 5 other plugins)

Utility:

   cordova-res : 0.8.0 (update available: 0.15.1)
   native-run  : 0.2.9 (update available: 1.0.0)

System:

   NodeJS : v10.16.3 (C:\Program Files\nodejs\node.exe)
   npm    : 6.9.0
   OS     : Windows 10
liamdebeasi commented 4 years ago

Thanks for the issue. I am going to close this as this is not a bug in Ionic Framework. The first issue is occurring when you try to inject IonRouterOutlet outside of your app's ion-router-outlet component. For example, this can happen if you try to inject it into your app.component.ts file.

Injecting IonRouterOutlet requires that you inject it into a component inside of the ion-router-outlet element you want to have access to.

indraraj26 commented 4 years ago

app.component is the only which will not be killed during the lifetime of app. Where should i inject IonRouterOutlet and listen to back button ?

this.platform.backButton.subscribeWithPriority(-1, async (_) => {
                console.log(
                    this._ionRouterOutlet.component,
                );
                if (!this._ionRouterOutlet.canGoBack()) {
                    await this._app.minimize();
                }
            });
liamdebeasi commented 4 years ago

If you want to use the dependency injection, you need to inject it into a component that exists inside of ion-router-outlet. Otherwise, you can use a querySelector to select the component yourself.

bfan1256 commented 4 years ago

@liamdebeasi , how would you test the IonRouterOutlet in the spec.ts files? I keep getting the NullInjection errors as described above.

rtbm commented 4 years ago

You can define a property in the app.component.ts like: @ViewChild(IonRouterOutlet, { static : true }) routerOutlet: IonRouterOutlet;

and then use it like this.routerOutlet.canGoBack().

Unfortunately querySelector is not a proper answer and got lost me for a while. Hopes that it'll be helpfull for anyone who gets here like me :)

indraraj26 commented 4 years ago

Thanks a lot @rtbm for sharing the way to get rid of querySelector

ionitron-bot[bot] commented 3 years ago

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.