Ionic Split Pane Component – Part 1

Update (March 8, 2017)

Ionic has released version 2.2 of the framework! In addition, to support Angular 2.4.8, the split pane component is now included! Details on this upgrade see the release notes.

Update (February 28, 2017)

The component has been renamed from ion-split-panel to ion-split-pane. I will the GitHub repo soon. Also, note you will need to use this build of Ionic: npm install –save ionic-angular@2.1.0-201702281739
Recently the Ionic team released a preview of the split pane component in this blog post, I want to take a look at it in a bit more depth. For those not familiar with this visual design pattern, it is very similar to the side menu layout. The main difference is that menu usually remains onscreen. Gmail is a great example of this layout pattern. As Ionic begins to expand from the mobile space into progressive web apps and even the desktop, this layout is a common pattern.
Since this component is similar to the side menu layout, let’s scaffold our app using that template.
$ ionic start splitPaneDemo sidemenu --v2
Once the project is ready, go ahead and change the working directory to splitPaneDemo. Since the component is still under development, we need to swap out the release version of Ionic for the nightly build.
$ npm install --save ionic-angular
With our copy of Ionic replaced, go ahead and open app.html. There are just a few things we need to do to convert our side menu template to use the split pane layout.
< ion-split-pane >
  < ion-menu [content]="content" when="xs" >
    < ion-header >
      < ion-toolbar >
        < ion-title >Menu< /ion-title >
      < /ion-toolbar >
    < /ion-header >

    < ion-content >
      < ion-list >
        < button menuClose ion-item *ngFor="let p of pages"    
         (click)="openPage(p)" >
        {{p.title}}
      < /button >
      < /ion-list >
    < /ion-content >

  < /ion-menu >

  < ion-nav main [root]="rootPage" #content swipeBackEnabled="false" >< /ion-nav >
< /ion-split-pane >
We need to tell the component when the ‘menu’ should be displayed. The typical UX flow is to have the split pane hide when the screen or viewport become reduced. The component has the following breakpoints defined:
label min-width
xs 0px
sm 576px
md 768px
lg 992px
xl 1200px
never  –
By passing one of these strings to our when attribute we can control when our menu is shown. Another item to note, the min-width our split pane is 270px and it set to be no larger than 28% of the viewport. All these values are defined within the components SASS files.
< ion-menu [content]="content" when="xs" >
The last adjustment we need to denote the ‘main‘ content for the split pane. For this, just include the main directive to
< ion-nav main [root]="rootPage" #content swipeBackEnabled="false" >
 Running $ ionic serve, will produce this:
screencapture-localhost-8100-1487963384735

The sidemenu template being rendered as a split pane layout.

If you include menuToggle on the header of the main pages, the split pane will understand that directive and use it when the split pane is hidden.
Now, this initial sample is not much more than sidemenu with the expose-aside-when value that was available in v1. Let’s explore a more complex sample.
In this sample, we will enable the split pane to have its own navigation stack that it independent of the main content’s navigation stack. This was a design pattern that I was never able to build using Ionic v1. I had several app ideas that would have been a perfect match for it (yes, I am starting to flesh those apps out now).
First, let’s generate a collection of new pages using the Ionic generate command:
$ ionic g page Main
$ ionic g page SideNav
$ ionic g page SideNav2
$ ionic g page View1
 Next, make sure you update app.module.ts to import these new views. In addition, take note of setting both the root and sideRoot variables, as well as setting myApp within the @NgModule.
import { NgModule, ErrorHandler, Component } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MainPage } from '../pages/main/main';
import { SideNavPage } from '../pages/side-nav/side-nav';
import { SideNav2Page } from '../pages/side-nav2/side-nav2';
import { View1Page } from '../pages/view1/view1';

@Component({
 templateUrl: 'app.html'
})
export class myApp {
 root = MainPage;
 sideRoot = SideNavPage;
}

@NgModule({
 declarations: [
 myApp,
 MainPage,
 SideNavPage,
 SideNav2Page,
 View1Page
 ],
 imports: [
 IonicModule.forRoot(myApp)
 ],
 bootstrap: [IonicApp],
 entryComponents: [
 myApp,
 MainPage,
 SideNavPage,
 SideNav2Page,
 View1Page
 ],
 providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
Next, let’s adjust the app.html file for our new structure. Instead of directly defining the content of the split pane, we are now just including an element and setting its root property to sideRoot. We will use this reference to populate the content.
< ion-split-pane when="sm" >

  < ion-menu [content]="content" >
    < ion-nav [root]="sideRoot" >< /ion-nav >
  < /ion-menu >

  < ion-nav [root]="root" main #content >< /ion-nav >

< /ion-split-pane >

Since both of these containers had their own navigation stack, we can move through our application independently. Let’s give our various pages some content first so we can see all this in action.

Change side-nav.html to:

< ion-header >

< ion-navbar >
< ion-title >Components< /ion-title >
< /ion-navbar >

< /ion-header >


< ion-content >
< ion-list >
< button menuClose ion-item *ngFor="let p of pages" (click)="displaySubNav(p)" >
{{p.title}}
< /button >
< /ion-list >
< /ion-content >

and side-nav.ts to

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { SideNav2Page } from '../side-nav2/side-nav2';

@Component({
 selector: 'page-side-nav',
 templateUrl: 'side-nav.html'
})

export class SideNavPage {
 pages: Array<{ title: string, component: any }>;

 constructor(public navCtrl: NavController, public navParams: NavParams) {
 this.pages = [
{ title: 'Action Sheets', component: SideNav2Page },
{ title: 'Alerts', component: SideNav2Page },
{ title: 'Badges', component: SideNav2Page },
{ title: 'Buttons', component: SideNav2Page },
{ title: 'Cards', component: SideNav2Page },
{ title: 'Checkbox', component: SideNav2Page },
{ title: 'DateTime', component: SideNav2Page },
{ title: 'FABs', component: SideNav2Page },
{ title: 'Gestures', component: SideNav2Page },
{ title: 'Grid', component: SideNav2Page },
{ title: 'Icons', component: SideNav2Page },
{ title: 'Inputs', component: SideNav2Page },
{ title: 'Lists', component: SideNav2Page },
{ title: 'Loading', component: SideNav2Page },
{ title: 'Menus', component: SideNav2Page },
{ title: 'Modals', component: SideNav2Page },
{ title: 'Navigation', component: SideNav2Page },
{ title: 'Popover', component: SideNav2Page },
{ title: 'Radio', component: SideNav2Page },
{ title: 'Range', component: SideNav2Page },
{ title: 'Searchbar', component: SideNav2Page },
{ title: 'Segment', component: SideNav2Page },
{ title: 'Select', component: SideNav2Page },
{ title: 'Slides', component: SideNav2Page },
{ title: 'Tabs', component: SideNav2Page },
{ title: 'Toast', component: SideNav2Page },
{ title: 'Toggle', component: SideNav2Page },
{ title: 'Toolbar', component: SideNav2Page }
];

}

 displaySubNav(thePage:any) {
  this.navCtrl.push(thePage.component);
 }
}

Next, let’s change the side-nav2.html file to be this:

< ion-header >

 < ion-navbar >
  < ion-title >Details< /ion-title >
 < /ion-navbar >

< /ion-header >

< ion-content >
 < p >New content< /p >
< /ion-content >

We don’t need to change the side-nav2.ts for this simple demo. Let’s change our main.html file this:

< ion-header >

 < ion-navbar >
  < ion-title >Main< /ion-title >
 < /ion-navbar >

< /ion-header >

< ion-content padding >
 < button ion-button primary (click)="goNewView()" >Go View 1< /button >
< /ion-content >

and the main.ts to:

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { View1Page } from '../view1/view1';

@Component({
 selector: 'page-main',
 templateUrl: 'main.html'
})
export class MainPage {

constructor(public navCtrl: NavController, public navParams: NavParams) { }

ionViewDidLoad() {
 console.log('ionViewDidLoad MainPage');
 }

goNewView() {
 this.navCtrl.push(View1Page);
 }
}

Save the files, and try it out.

split-panel-demo

Independent Ionic navigation in the split pane layout.

The source code for this demo is available at my GitHub Repo.

Advertisements

3 comments

  1. Hey!, this is great.I’m actually using this already on a project.

    I got this to work,however, I haven’t figured out how to push a PageComponent on to the Main content on the right from a sub item on the left side of the split pane.

    All of the references to @Viewchild(Nav) or this.app.getRootNav() ot this.nav.parent,SetRoot() only have effect on the left side navigation.

    How would you go about calling nav.setRoot(Page) on to the main right side area?

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s