Ionic 2: Using tabs to navigate

This is a tutorial focusing on adding ionic tabs manually to an ionic 2 project.

Some thoughts on ionic tabs

Think of the tabs as a wrapper, and any pages you want tabbed have to be added to this wrapper.

You don’t add tabs to your pages, you add your pages to your tabs.

Let’s get started…

Here’s a quick little lightweight tutorial. This will help you add tabs to an ionic app that does not already have tabs.

You won’t need much knowledge of typescript and angular 2, but it is advised that you have a basic understanding of these in order to develop with Ionic 2.

You will definitely need to know how to use your terminal/command tool, in order to run the commands to run ionic 2.

You can always skip this tutorial but taking a useful shortcut and just create an ionic app with tabs by running:

1
ionic start [yourAppName] tabs --v2

If you get stuck in a situation like me, where the project you found yourself working on did not already come with tabs, then continue below.

Setup

Make sure you have:

Ionic 2 set up (not Ionic 1)

Follow this

https://ionicframework.com/docs/v2/setup/installation/

Scaffold a blank ionic 2 app

To create your first blank ionic app run

1
ionic start navigation-app blank --v2

NB: Remember the —v2 else you will be creating an ionic 1 application.

You should get this response

  Your Ionic app is ready to go!

Run your application

Navigate into your new application’s folder:

1
cd navigation-app/

Test that your application is working

Run

1
ionic serve

This should open up a browser window and display your newly created mobile application. It will be just a blank page with a grey header at the top that says “Ionic Blank” and some copy on the page below saying something like “The world is your oyster”.

If that does not happen, you may need to investigate your ionic 2 installation. And you may need to just check your start command you just ran.

You should have the following folder in the root of your application:

1
/src

This is the folder you want to do your development in. Do not do changes in a /www folder.

Add the tabs navigation

Generate a tabs navigation component. I personally would not add it as a page, because it is technically not a page. You can add it as a page, I just like my code to be semantic, if I go to the pages folder, every ts file in there should be a page. I don’t want to guess what I am working with.

Use the handy ionic 2 generator to auto generate the component:

Note: use Pascal case for the name of your component in the command line/terminal:

1
ionic g component MyTabs

This will generate a folder called “my-tabs”.

In the components folder of your ionic 2 application.

1
2
3
4
5
6
7
8
9
10
11
src/

    components/

        my-tabs/

            my-tabs.html

            my-tabs.ts

            my-tabs.scss

Note, the .scss file is your component’s SASS file, editing the SASS file is not part of this tutorial’s scope.

Important!

Add to /src/app/app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { NgModule, ErrorHandler } from '@angular/core';

import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';

import { MyApp } from './app.component';

import { HomePage } from '../pages/home/home';

import { MyTabsComponent } from '../components/my-tabs/my-tabs';

@NgModule({

  declarations: [

    MyApp,

    HomePage,

    MyTabsComponent

  ],

  imports: [

    IonicModule.forRoot(MyApp)

  ],

  bootstrap: [IonicApp],

  entryComponents: [

    MyApp,

    HomePage,

    MyTabsComponent

  ],

  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]

})

export class AppModule {}

The important parts:

1
import { MyTabsComponent } from '../components/my-tabs/my-tabs';

and adding MyTabsComponent to “declarations” and “entryComponents”.

Update the landing page

Updating the landing page to be your MyTabs component:

So lets say you want the first page to be this tabs navigation that we are creating. In order for that to happen we need to edit app.component.ts in your /src/app folder:

You will replace Home with MyTabs.

Make sure it has the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Component } from '@angular/core';

import { Platform } from 'ionic-angular';

import { StatusBar, Splashscreen } from 'ionic-native';

import { MyTabsComponent } from '../components/my-tabs/my-tabs';

@Component({

  templateUrl: 'app.html'

})

export class MyApp {

  rootPage = MyTabsComponent;

  constructor(platform: Platform) {

    platform.ready().then(() => {

      // Okay, so the platform is ready and our plugins are available.

      // Here you can do any higher level native things you might need.

      StatusBar.styleDefault();

      Splashscreen.hide();

    });

  }

}

The important parts:

1
import { MyTabs } from './components/my-tabs/my-tabs';

and

1
<span class="Apple-converted-space">  </span>rootPage = MyTabs;

If you get an error saying No component factory found for

You need to add the component declaration to app.module.ts as specified above.

Your application will now refresh and you will see just “Hello World”, we need to add our tabs structure to the MyTabs component. Or a black screen, it’s ok, don’t panic, we need to edit some more stuff, carry on below.

Add the tabs navigation

Have a look at the ionic 2 tabs documentation:

https://ionicframework.com/docs/v2/api/components/tabs/Tabs/

You will see you need this in your MyTabs class in my-tabs.ts:

1
2
3
4
5
<span class="Apple-converted-space">  </span>tab1Root = Page1;

<span class="Apple-converted-space">  </span>tab2Root = Page2;

<span class="Apple-converted-space">  </span>tab3Root = Page3;

And in your my-tabs.html:

1
2
3
4
5
  tab1Root = Page1;

  tab2Root = Page2;

  tab3Root = Page3;

Add those into the files mentioned above and as indicated in the documentation examples.

You will see errors appear, because Page1, Page2 and Page3 do not exist.

Lets just get it to work before adding pages.

Update your my-tabs.ts file to say:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Component } from '@angular/core';

import { HomePage } from '../../pages/home/home'

/*

  Generated class for the MyTabs component.

  See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html

  for more info on Angular 2 Components.

*/

@Component({

  selector: 'my-tabs',

  templateUrl: 'my-tabs.html'

})

export class MyTabsComponent {

  text: string;

  tab1Root = HomePage;

  constructor() {

  }

}

The important parts:

1
import { HomePage } from '../../pages/home/home'

and

1
  tab1Root = HomePage;

Also let’s update our html:

Makes sure your my-tabs.html has only the following:

1
2
3
4
5
<ion-tabs>

  <ion-tab [root]="tab1Root"></ion-tab>

</ion-tabs>

Now you should see your Home page appear again on the application.

The reason you see your home page is because the MyTabs tabs component is now responsible for displaying the pages not your app.component.ts.

So to repeat the concept behind Ionic 2 Tabs and page navigation

Your tabs component will be what you route to, this is what you display on screen, then the tabs hold the responsibility to pop and push the pages on and off the screen as the user clicks through them.

You do not attach the tabs to a page, but rather you attach the pages to the tabs.

Add more pages

We need to create the Page1, Page2 and Page3 pages. You can have any number of pages you want, just remember this is a mobile application and space is limited.

We already have a Home page which we can just edit. Let’s create an About page and a ContactUs page. Then we will replace Page1, Page2 and Page3 with those pages.

Use the useful ionic generator again

Remember to use Pascal case for you page name

1
2
ionic g page About
ionic g page ContactUs

Now you will see three new folders in your pages folder of your ionic project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/src

/pages

/home

home.html

home.scss

home.ts

/about

about.html

about.scss

about.ts

/contact-us

contact-us.html

contact-us.scss

contact-us.ts

We want to import these new pages into the my-tabs.ts file.

Update your my-tabs.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { Component } from '@angular/core';

import { HomePage } from '../../pages/home/home'

import { AboutPage } from '../../pages/about/about'

import { ContactUsPage } from '../../pages/contact-us/contact-us'

/*

  Generated class for the MyTabs component.

  See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html

  for more info on Angular 2 Components.

*/

@Component({

  selector: 'my-tabs',

  templateUrl: 'my-tabs.html'

})

export class MyTabsComponent {

  text: string;

  tab1Root = HomePage;

  tab2Root = AboutPage;

  tab3Root = ContactUsPage;

  constructor() {

  }

}

Update your my-tabs.html

1
2
3
4
5
6
7
8
9
<ion-tabs>

  <ion-tab [root]="tab1Root"></ion-tab>

  <ion-tab [root]="tab2Root"></ion-tab>

  <ion-tab [root]="tab3Root"></ion-tab>

</ion-tabs>

Important!

Add to /src/app/app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { NgModule, ErrorHandler } from '@angular/core';

import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';

import { MyApp } from './app.component';

import { HomePage } from '../pages/home/home';

import { AboutPage } from '../pages/about/about';

import { ContactUsPage } from '../pages/contact-us/contact-us';

import { MyTabsComponent } from '../components/my-tabs/my-tabs';

@NgModule({

  declarations: [

    MyApp,

    HomePage,

    AboutPage,

    ContactUsPage,

    MyTabsComponent

  ],

  imports: [

    IonicModule.forRoot(MyApp)

  ],

  bootstrap: [IonicApp],

  entryComponents: [

    MyApp,

    HomePage,

    AboutPage,

    ContactUsPage,

    MyTabsComponent

  ],

  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]

})

export class AppModule {}

The important parts:

1
2
3
import { AboutPage } from '../pages/about/about';

import { ContactUsPage } from '../pages/contact-us/contact-us';

And adding AboutPage and ContactUsPage to the declarations and entryComponents sections.

Adding title and icons to the tabs

You now have 3 tabs at the bottom of the screen, except you can’t see them. If you click on the bottom grey bar you will navigate to the different pages you created, but you won’t know what you are clicking on.

Add tabTitle and tabIcon attributes:

1
2
3
4
5
6
7
8
9
<ion-tabs>

  <ion-tab [root]="tab1Root" tabTitle="Home" tabIcon="home"></ion-tab>

  <ion-tab [root]="tab2Root" tabTitle="About" tabIcon="help"></ion-tab>

  <ion-tab [root]="tab3Root" tabTitle="Contact Us" tabIcon="contact"></ion-tab>

</ion-tabs>

Now you will be able to clearly see your three tabs.

To find more ionic 2 icons search this page:

https://ionicframework.com/docs/v2/ionicons/

Bonus:

Making tabs dynamic and sneaking in some polymorphism.

My brain automatically wants to make things polymorphic. I see a pattern like “tab1Root”, “tab2Root” and “tab3Root” and I’m immediately thinking let’s make that a dynamic array that can easily be extended and changed without touching the html.

To do that is very simple.

All we need is an array of objects, and an *ngFor on the <ion-tab> tag.

Update the my-tabs.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import { Component } from '@angular/core';

import { HomePage } from '../../pages/home/home'

import { AboutPage } from '../../pages/about/about'

import { ContactUsPage } from '../../pages/contact-us/contact-us'

/*

  Generated class for the MyTabs component.

  See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html

  for more info on Angular 2 Components.

*/

@Component({

  selector: 'my-tabs',

  templateUrl: 'my-tabs.html'

})

export class MyTabsComponent {

  text: string;

  tab1Root = HomePage;

  tab2Root = AboutPage;

  tab3Root = ContactUsPage;

  tabs = [

    {

      root: HomePage,

      title: 'Home',

      icon: 'home'

    },

    {

      root: AboutPage,

      title: 'About',

      icon: 'help',

    },

    {

      root: ContactUsPage,

      title: 'Contact Us',

      icon: 'contact'

    }

  ];

  constructor() {

  }

}

Update the my-tabs.html

1
2
3
4
5
<ion-tabs>

  <ion-tab *ngFor="let tab of tabs" [root]="tab.root" tabTitle="{{tab.title}}" tabIcon="{{tab.icon}}"></ion-tab>

</ion-tabs>

Bonus bonus:

I did also push that a bit further and added callbacks to the tabs, so when you click on one that needs to triggers an action like a ActionSheetController instead of a redirect. If you are interested in this solution let me know and I’ll share it as well.

Ionic 2 Testing

How do we write tests for ionic 2 tabs?

We don’t talk about ionic 2 testing 😐

Kidding, I still have to wrap my head around ionic 2 testing, so as soon as I have that figured out I will create a follow up post on how to write the Ionic 2 unit tests.

Onwards! To mobile development success.