-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Description
Bug Report
Ionic version:
[x] 5.6.9
Current behavior:
If routes are defined with optional segment values then the ionic back button can result in errors.
Use case: A page that has optional parameters and handles more than one route.
Because there is no way to specify optional segments in routes the page gets mapped to multiple url values. For example:
<ion-router useHash>
<ion-route url="/:s1/:s2" component="my-page" />
<ion-route url="/:s1" component="my-page" />
<ion-route url="" component="my-page" />
</ion-router>Here is the sequence of steps:
- Navigate to
/a. The component renders with props{s1: 'a', s2: undefined}as expected. - Push
/a/bonto the navigation stack. Another instance of the page renders with{s1: 'a', s2:'b'}as expected. - Click on
<ion-back-button>on the page. The prior page is displayed correctly but the url does not get updated so it is now incorrect.
The following entry appears in the log:
[ion-router] router could not match path because some required param is missing
This error occurs because it finds a different route than the one that matched when the page was displayed.
The following code is where the error occurs:
// ion-router.tsx
async navChanged(direction: RouterDirection): Promise<boolean> {
if (this.busy) {
console.warn('[ion-router] router is busy, navChanged was cancelled');
return false;
}
const { ids, outlet } = await readNavState(window.document.body);
const routes = readRoutes(this.el);
const chain = routerIDsToChain(ids, routes);
if (!chain) {
console.warn('[ion-router] no matching URL for ', ids.map(i => i.id));
return false;
}
const path = chainToPath(chain);
if (!path) {
console.warn('[ion-router] router could not match path because some required param is missing');
return false;
}
this.setPath(path, direction);
await this.safeWriteNavState(outlet, chain, ROUTER_INTENT_NONE, path, null, ids.length);
return true;
}When the back button executes, navChanged() is called and the following happens:
- The calculated value of
chainis the route with all of the segments (<ion-route url="/:s1/:s2" component="my-page" />) vs. the route that matched for the first page that was displayed. - The call to
chainToPath()fails because the page being displayed only specifies a value fors1and it thinkss2should be required. - The method exits without setting the path or calling safeWriteNavState.
It looks like the method is assuming that it can cancel the navigation because it thinks there is no match but in reality <ion-nav> has already updated the displayed page.
Expected behavior:
- The back button should result in the correct url that matches the displayed content
- Other failure conditions (e.g. busy) should also ensure that the state is consistent
One other issue that could occur:
- Because of the lag in updating the url (based on animation delays?) it is possible for a page to render based on a url that is different from the original route it matched so there can be tricky timing issues if an app attempts to parse information from the current url.