Passing Data Between Tabs in Ionic 2
When using tabs in Ionic 2, each one of them contains a page that doesn't know anything about the other pages nor their common parent page hosting the tabs. This makes it challenging to switch tabs or pass data between them.
Passing Values from Parent to Child Page
To pass data from the parent page to a tab, there is rootParams
input property on Tab
component. Its value will be passed to the child page via the injected NavParams
object. To pass an id
value to the child page, the parent page needs to bind it to rootParams
:
export class TabsPage {
tab1Root = Page1;
tab2Root = Page2;
tab2Params = { id: 1 };
}
<ion-tabs>
<ion-tab [root]="tab1Root" tabTitle="Page 1"></ion-tab>
<ion-tab [root]="tab2Root" [rootParams]="tab2Params" tabTitle="Page 2"></ion-tab>
</ion-tabs>
The child page can then read the value in its constructor:
import { NavParams } from 'ionic-angular';
export class Page2 {
id: number;
constructor(navParams: NavParams) {
this.id = navParams.get('id');
}
}
Switching to a Different Tab from Code
Tabs
component provides a convenient select
method for changing the currently selected tab, however there is no obvious way to access it from the child page. Inspecting the injected NavController
instance in the child page reveals that its parent is actually the Tabs
component we are looking for:
import { NavController } from 'ionic-angular';
export class Page1 {
constructor(private navCtrl: NavController) {}
changeTab() {
(this.navCtrl.parent as Tabs).select(1);
}
}
Although this works, it relies on undocumented Ionic internals, and can easily break in future versions. It also doesn't provide a way to pass along additional data, e.g. a different id
value.
Using Events
Fortunately, Ionic 2 comes with a publish-subscribe based message passing system, which can be used instead. The child page can publish a message to a specific topic, notifying the parent page about the tab change request:
import { Events } from 'ionic-angular';
export class Page1 {
constructor(private events: Events) {}
changeTab() {
this.events.publish('change-tab', 1, 2);
}
}
The parent page can subscribe to this topic and change the tab when it receives the message:
import { ViewChild } from '@angular/core';
import { Tabs, Events } from 'ionic-angular';
export class TabsPage {
// reference component in page template
@ViewChild(Tabs) tabs: Tabs;
tab1Root = Page1;
tab2Root = Page2;
tab2Params = { id: 1 };
constructor(events: Events) {
events.subscribe('change-tab', (tab, id) => {
this.tabParams.id = id;
this.tabs.select(tab);
});
}
}
This will only work, if the requested tab hasn't been opened before. Otherwise, the page is already initialized and will not read the new id
value. To be notified about it, it must subscribe to the same topic:
import { NavParams, Events } from 'ionic-angular';
export class Page2 {
id: number;
constructor(navParams: NavParams, events: Events) {
this.id = navParams.get('id');
events.subscribe('change-tab', (tab, id) => {
this.id = id;
});
}
}
If you're planning to use message passing in multiple places in your application, you should come up with a good naming policy for the message topics to make the meaning of each message as clear as possible. You could even declare the names as constants to avoid typos.