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.97k stars 13.52k forks source link

bug: ion-tab-button not selected when using routeParams #18726

Open MartineFrancken opened 5 years ago

MartineFrancken commented 5 years ago

Bug Report

Ionic version:

[x] 4.6.0 (ionic/angular)

Current behavior: When using a param in [tab] of an ion-tab-button, the ion-tab-button is not recognized as selected when navigating to the tab. Example: <ion-tab-button [tab]='patient/0'></ion-tab-button> When clicking this button, 'patient/0' route is called and the tab patient/0 is shown. But the ion-tab-button is not recognized as selected.

Expected behavior: I would expect that the ion-tab-button is recognized as selected.

Other information: I was able to find that an stackId is used internally to decide if an ion-tab-button is selected. stackId is looking to the url and only taking the part 'patient' and ignores '/0'.

Ionic info:

Ionic:
   Ionic CLI                     : 5.0.3 (/usr/local/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.6.0
   @angular-devkit/build-angular : 0.13.9
   @angular-devkit/schematics    : 7.3.9
   @angular/cli                  : 7.3.9
   @ionic/angular-toolkit        : 1.5.1

Cordova:
   Cordova CLI       : 9.0.0 (cordova-lib@9.0.1)
   Cordova Platforms : ios 4.5.5
   Cordova Plugins   : cordova-plugin-ionic 5.2.1, cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 3.1.2, (and 9 other plugins)

Utility:
   cordova-res : not installed
   native-run  : not installed

System:
   ios-deploy : 1.9.4
   ios-sim    : 8.0.1
   NodeJS     : v10.15.3 (/usr/local/bin/node)
   npm        : 6.9.0
   OS         : macOS Mojave
   Xcode      : Xcode 10.2.1 Build version 10E1001
liamdebeasi commented 5 years ago

Thanks for the issue! The tab property is not meant to represent the actual route. It should map to a top level path in your router configuration.

Please see the documentation for more information: https://ionicframework.com/docs/api/tabs/#router-integration

Does this resolve your issue?

MartineFrancken commented 5 years ago

No, this does not solve this issue, since it is mentioned in the docs that it should reference the route:

When used with Angular's router the tab property of the ion-tab-button should be a reference to the route path.

liamdebeasi commented 5 years ago

Hi there,

"route path" is not the same this as the route. In the example directly beneath the line you quoted, it shows the tab value as being set to schedule, and in the TypeScript code included, it shows schedule as being the path.

If you had something like schedule/24 that would be the route, but schedule would still remain the path.

MartineFrancken commented 5 years ago

In the code related to the example I gave with 'patient/0', the path is declared with the following code: path: 'patient/:id',

It does work fine for situations where ':id' is not required, for other pages, but I need the routeParam for this situation, since multiple patients can be added to the tab bar. If 0 or 1 should not be part of the value [tab], where should it be provided then to be able to navigate to 'patient/0' or 'patient/1' ?

liamdebeasi commented 5 years ago

Can you send the code for how your router is set up?

MartineFrancken commented 5 years ago

const routes: Routes = [ { path: '', component: TripPage, canActivate: [AuthenticationGuard], children: [ { path: '', redirectTo: 'info', pathMatch: 'full' }, { path: 'patient/:id', loadChildren: './patient/patient.module#PatientPageModule' }, { path: 'details/:id', loadChildren: './details/details.module#DetailsPageModule' }, { path: 'info', loadChildren: './info/info.module#InfoPageModule' }, { path: 'location', loadChildren: './location/location.module#LocationPageModule' }, { path: 'objective', loadChildren: './objective/objective.module#ObjectivePageModule' }, { path: 'siwha', loadChildren: './siwha/siwha.module#SiwhaPageModule' }, { path: 'note', loadChildren: './note/note.module#NoteModule' }, { path: 'situation/:id', loadChildren: './situation/situation.module#SituationModule' } ] } ];

This is a subset of our routes in the application. The TripPage contains the tabs.

liamdebeasi commented 5 years ago

Thanks for the follow up. It's a bit of a gray area, but I'm inclined to say this is a bug since routing works, yet the tab does not appear to be activated.

Here's a (hacky) workaround for now:

<ion-tab-button tab="tab2" (click)="navigate()">
  <ion-icon name="apps"></ion-icon>
  <ion-label>Tab Two</ion-label>
</ion-tab-button>

and then in your TypeScript file:

import { Router } from '@angular/router';

...

public navigate() {
  setTimeout(() => {
    // replace 123 with a variable or whatever the ID should be
    this.router.navigate(['tabs', 'tab2', '123']);
  });
} 

If this causes some jank, you could also try wrapping the navigate call in a requestAnimationFrame rather than a setTimeout and see if that helps.

tlaverdure commented 3 years ago

Ran into this issue today. If href is set on the ion-tab-button component shouldn't that override the tab property in terms of routing? Could it possibly be that ionic-angular doesn't have an ion-router tag to use as a selector but an ion-router-outlet?

https://github.com/ionic-team/ionic-framework/blob/8e0e5da7407adecb7471b3a6b0ac059337761355/core/src/components/tabs/tabs.tsx#L173-L183

davidgeary commented 1 year ago

FYI, just updated to v7.0.0 and this is still an issue.

One minor point - the workaround above does work but if the route is configured to always take a routeParam, clicking on the tab button results in an error in the console:

Error: NG04002: Cannot match any routes. URL Segment: 'patient'

The default route handling of the ion-tab-button is still being triggered in addition to the click handler, so the handler needs to cancel that, e.g.

  public navigateTo(event: Event, commands: any[]): void {
    event.stopImmediatePropagation();

    setTimeout(() => {
      this.router.navigate(commands);
    });
  }