Ionic 3 > Master-Detail App using the split-pane component

Getting started

1. Tweak ‘split-pane’ component styles (LESS)

.split-pane-side:not(ion-menu) {
display: initial;
}
.split-pane-main {
display: none;
}
.split-pane-visible {
.split-pane-main {
display: block;
}
}

2. Add a ‘Proxy’ navigation service

import { Injectable } from '@angular/core';
import { Nav } from 'ionic-angular';
import { PlaceholderPage } from '../pages/placeholder/placeholder';
import { _DetailPage } from '../pages/_DetailPage';
@Injectable()
export class NavProxyService {
_masterNav: Nav = null;
get masterNav(): Nav {
return this._masterNav;
}
set masterNav(value: Nav) {
this._masterNav = value;
}
_detailNav: Nav = null;
get detailNav(): Nav {
return this._detailNav;
}
set detailNav(value: Nav) {
this._detailNav = value;
}
_isOn: boolean = false;
get isOn(): boolean {
return this._isOn;
}
set isOn(value: boolean) {
this._isOn = value;
}
pushDetail(page: any, params: any) {
(this.isOn) ?
this.detailNav.setRoot(page, params):
this.masterNav.push(page, params);
}
pushMaster(page: any, params: any) {
this.masterNav.push(page, params);
}
onSplitPaneChanged(isOn) {
// set local 'isOn' flag...
this.isOn = isOn;
// if the nav controllers have been instantiated...
if (this.masterNav && this.detailNav) {
(isOn) ? this.activateSplitView() :
this.deactivateSplitView();
}
}
activateSplitView() {
let currentView = this.masterNav.getActive();
if (currentView.component.prototype
instanceof _DetailPage) {
// if the current view is a 'Detail' page...
// - remove it from the 'master' nav stack...
this.masterNav.pop();
// - and add it to the 'detail' nav stack...
this.detailNav.setRoot(
currentView.component,
currentView.data);
}
}
deactivateSplitView() {
let detailView = this.detailNav.getActive();
this.detailNav.setRoot(PlaceholderPage);
if (detailView.component.prototype instanceof _DetailPage) {
// if the current detail view is a 'Detail' page...
// ...so, not the placeholder page:
let index = this.masterNav.getViews().length;
// add it to the master view...
this.masterNav.insert(index,
detailView.component,
detailView.data);
}
}
}
...
import {
NavProxyService
} from '../services/NavProxy.service';
...
@NgModule({
...
providers: [
...
NavProxyService,
...
]
})
export class AppModule { }

3. ‘Mark’ pages as either ‘master’ or ‘detail’

export abstract class _MasterPage { }
export abstract class _DetailPage { }
...
@IonicPage()
@Component({
...
})
export class ItemsPage extends _MasterPage { ... }
...
@IonicPage()
@Component({
...
})
export class ItemPage extends _DetailPage { ... }

4. Add the ‘split-pane’ component to our app & listen for when it’s activated/deactivated

...
<ion-split-pane
(ionChange)="navProxy.onSplitPaneChanged($event._visible)">
<ion-nav [root]="masterPage"
#masterNav>
</ion-nav>
<ion-nav [root]="detailPage"
#detailNav main>
</ion-nav>
</ion-split-pane>
...

5. Wire it all together

import { Component, ViewChild } from '@angular/core';
...
import { NavProxyService } from '../services/NavProxy.service';
import { ItemsPage } from '../pages/items/items';
import { PlaceholderPage } from '../pages/placeholder/placeholder';
@Component({
...
})
export class MyApp {
// Grab References to our 2 NavControllers...
@ViewChild('detailNav') detailNav: Nav;
@ViewChild('masterNav') masterNav: Nav;
... constructor(
...
private navProxy: NavProxyService) {
platform.ready().then(() => {
...
// Add our nav controllers to
// the nav proxy service...
navProxy.masterNav = this.masterNav;
navProxy.detailNav = this.detailNav;
// set initial pages for
// our nav controllers...
this.masterNav.setRoot(ItemsPage,
{ detailNavCtrl: this.detailNav });
this.detailNav.setRoot(PlaceholderPage);
});
}
}
...
import { NavProxyService } from '../../services/NavProxy.service';
import {_MasterPage, ItemPage } from '../';
@IonicPage()
@Component({
...
})
export class ItemsPage extends _MasterPage {
constructor(public navCtrl: NavController,
public navParams: NavParams,
private navProxy: NavProxyService) {
super();
}
onItemSelected(item) {
// Rather than using:
// this.navCtrl.push(...)
// Use our proxy:
this.navProxy.pushDetail(ItemPage, item);
}
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store