Forcing Reload of Root Page in Ionic 4

February 14th 2020 Ionic 4+ Angular

Angular based routing in Ionic 4 introduces some gotchas if you're used to navigation in Ionic 3. Reinitializing the navigation stack by setting the root to the same page as it was before is one of those gotchas.

In Ionic 3, this caused the root page to get reloaded from scratch. That's not the case in Ionic 4. The root page can be set with a call to NavController::navigateRoot:

this.navCtrl.navigateRoot('/home');

However, this will only initialize home if a different page was set as root before the call. Otherwise, it will simply remove all the other pages from the navigation stack and keep the same instance of home as root. Neither the constructor nor ngOnInit will get called. If you're porting code from Ionic 3 and you relied on the page being reloaded (e.g. because a guest user now logged in and you want to reinitialize the page accordingly), this behavior will introduce a bug which you might not notice immediately.

One way to force the root page to reload is to ensure that its route is different. It's an approach similar to the one I used in a previous blogpost to repeat the same page in history multiple times when navigating a hierarchical structure.

A fake parameter can be added to the route to make it unique. Of course, you need to track the value of the parameter in order to change it on each call. If you're already wrapping all navigation calls in a service to make them easier to test, then this service can also hold the state of the parameter:

@Injectable({
  providedIn: 'root'
})
export class NavigationService {
  private counter = 0;

  constructor(private navCtrl: NavController) {}

  navigateHome() {
    this.counter += 1;
    this.navCtrl.navigateRoot(`/home/${this.counter}`);
  }
}

Incrementing the counter value before each call ensures a unique route every time the root is reset. Don't forget to modify the router configuration accordingly:

const routes: Routes = [
  { path: '', redirectTo: 'home/0', pathMatch: 'full' },
  {
    path: 'home/:counter',
    loadChildren: () => import('./home/home.module').then(m => m.HomePageModule)
  }
];

Notice that the root route redirectTo value must also include a the counter in order to match the home route.

With this change, the home page will reliably reload on every call of NavigationService::navigateHome. Even if the method is invoked from that root page itself, it will get reloaded and both its constructor and ngOnInit will get called. While you might take a different approach if you're writing a new Ionic 4 application, this workaround can be really useful for keeping the behavior the same when upgrading an application from Ionic 3 to Ionic 4. I know it works great in a project I'm working on.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License