Ionic | Cookbook

uploads/2016/12/ionic_1.png

Routing and Navigation

Basic Angular Router configuration

Create a routing module that is ‚visible‘ to all components in your app

app-routing.modules.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: '**', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home',  loadChildren: './home/home.module#HomePageModule'    },
    { path: 'list',  loadChildren: './list/list.module#ListPageModule'    },
    { path: 'about', loadChildren: './about/about.module#AboutPageModule' }
]

Update routing module imports and exports

app-routing.modules.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">imports { RouterModule, Routes } from '@angular/routes';
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})

Do not forget to import the routing module to you main app module

app.module

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { AppRoutingModule } from './app-routing.module';
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">imports:[
    AppRoutingModule
]

Add a router-outlet to indicate where the pages will be rendered

app.component.html

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><router-outlet></router-outlet>

Basics

src/app/app-routing.module.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
   { path: 'hello', component: HelloPage }
];

app.component.html

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><router-outlet></router-outlet>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">  // Regular Route
  { path: 'eager', component: MyComponent },

  // Lazy Loaded Route (Page)
  { path: 'lazy', loadChildren: './lazy/lazy.module#LazyPageModule' },

    // Redirect
  { path: 'here', redirectTo: 'there', pathMatch: 'full' }
];
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-button href="/hello">Hello</ion-button>
<a routerLink="/hello">Hello</a>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><a [routerLink]="['/product',product.id]"></a>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({ ... })
export class HomePage {
  constructor(private router: Router) {}

  go() {
    this.router.navigateByUrl('/animals');
  }
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
  // Regular Route
  { path: 'items/:id', component: MyComponent },
];
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-button href="/items/abc">ABC</ion-button>
<ion-button href="/items/xyz">XYZ</ion-button>

Passing parameter

Passing parameter with state service

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">export class ComponentA {
   constructor(private stateService: StateService) {}
   goToComponentB(): void {
        this.stateService.data = {...};
        this.router.navigate(['/b']);
    }
}
export class ComponentB implements OnInit {
    constructor(private stateService: StateService) {}
    ngOnInit(): void {
        this.data = this.stateService.data;
        this.stateService.data = undefined;
    }
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">export class ComponentA {
   constructor(private router: Router) {}
   
   goToComponentB(): void {
      this.router.navigate(['/b'], {state: {data: {...}}});
   }
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">go() {
   this.router.navigate(['../list'], { relativeTo: this.route });
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><a [routerLink]=”/b” [state]=”{ data: {...}}”>Go to B</a>

Extracting the data

The state property was added to <a href="https://angular.io/api/router/Navigation" rel="noreferrer noopener" target="_blank">Navigation</a> which is available through <a href="https://angular.io/api/router/Router#getcurrentnavigation" rel="noreferrer noopener" target="_blank">Router.getCurrentNavigation().extras.state</a>.

Problem is that getCurrentNavigation returns Navigation only during the navigation and returns null after the navigation ended. So the Navigationis no longer available in Component’s B onInit lifecycle hook. We need to read the data from browser’s history object:

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">history.state.data

Extract Data from Routes with ActivatedRoute

When working with dynamic data, you need to extract the params from the URL.

For example, you might want to read from the database when the user navigates to /items/:id, using the ID from the route to make a query.

Angular has an ActivatedRoute service that allows us to grab information from the current route as a plain object or Observable.

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({ ... })
export class ProfileComponent implements OnInit {

  id: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.id = this.route.snapshot.paramMap.get('id');
  }
}

Or if we need to react to changes, we can subscribe to an Observable.

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">ngOnInit() {
   this.route.paramMap.subscribe(params => {
      this.products.forEach((p: Product) => {
        if (p.id == params.id) {
          this.product = p;
        }
      });
    });
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">ngOnInit() {
   this.products.forEach((p: Product) => {
      if (p.id == this.route.snapshot.params.id) {
         this.product = p;
      }
   });
}

Migrate from Ionic X to Ionic 4 Routing

Set Root

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-button href="/support" routerDirection="root">

or in class

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">this.navCtrl.navigateRoot('/support');

Push

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-button href="/products/12" routerDirection="forward">
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">this.navCtrl.navigateForward('/products/12');

Pop

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-button href="/products" routerDirection="backward">
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-back-button defaultHref="/products"></ion-back-button>

Navigate backwards programatically:

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">this.navCtrl.navigateBack('/products');

Routing in Tabs

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">{
  path: 'contact',
  outlet: 'modal',
  component: ContactModal
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">http://.../(modal:contact)

Lazy Loading

Code Snippets

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">// home.module.ts
@NgModule({
  imports: [
    IonicModule,
    RouterModule.forChild([{ path: '', component: HomePage }])
  ],
  declarations: [HomePage]
})
export class HomePageModule {}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">// app.module.ts
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    RouterModule.forRoot([
      { path: 'home', loadChildren: './pages/home/home.module#HomePageModule' },
      { path: '', redirectTo: 'home', pathMatch: 'full' }
    ])
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Code Snippet

app-routing.module.ts
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
  { path: 'about', loadChildren: './about/about.module#AboutPageModule' },
];
about/about.module.ts
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
  { path: '', component: AboutPage },
];

Using Guards

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean {

    const loggedIn = false; // replace with actual user auth checking logic

    if (!loggedIn) {
      this.router.navigate(['/']);
    }

    return loggedIn;
  }
}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
  { path: 'special', component: SpecialPage, canActivate: [AuthGuard] },
];

Troubleshooting of Routing

Enable tracing

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="4" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""> @NgModule({
    imports: [
        RouterModule.forRoot(routes, 
            { enableTracing: true }
        )],
    exports: [RouterModule],
})
export class AppRoutingModule {}

Common Errors and mistakes

Placing global routing patterns at the front ot routing array

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="3" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: '**', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomePageComponent },

Finding the right path is a sequential process in search all entries in route[] and select the first with a matting path. So, in our wrong example, every path matches the common pattern ‚**‘.

Solution: Put this matting pattenr at the end of the routes[] array

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="4" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomePageComponent },
    { path: '**', redirectTo: '/home', pathMatch: 'full' },

Storage

Configuration

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { IonicStorageModule } from '@ionic/storage';

@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    IonicStorageModule.forRoot()
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    // ...
  ],
  providers: [
    // ...
  ]
})
export class AppModule {}
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">Finally, inject it into any of your components or pages:

import { Storage } from '@ionic/storage';

export class MyApp {
  constructor(private storage: Storage) {
      storage.set('name', 'Max');

      storage.get('age').then((val) => {
          console.log('Your age is',  val);
});
}
}

Code sample

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">class MyClass {
  constructor(public storage: Storage) {}

  async setData(key, value) {
    const res = await this.storage.set(key, value);
    console.log(res);
  }

  async getData(key) {
    const keyVal = await this.storage.get(key);
    console.log('Key is', keyVal);
  }
}

Storage with Capacitor

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Plugins } from '@capacitor/core';

const { Storage } = Plugins;

async setObject() {
  await Storage.set({
    key: 'user',
    value: JSON.stringify({
      id: 1,
      name: 'Max'
    })
  });
}

async getObject() {
  const ret = await Storage.get({ key: 'user' });
  const user = JSON.parse(ret.value);
}

async setItem() {
  await Storage.set({
    key: 'name',
    value: 'Max'
  });
}

async getItem() {
  const value = await Storage.get({ key: 'name' });
  console.log('Got item: ', value);
}

async removeItem() {
  await Storage.remove({ key: 'name' });
}

async keys() {
  const keys = await Storage.keys();
  console.log('Got keys: ', keys);
}

async clear() {
  await Storage.clear();
}

Components

Alerts

Code Snippets

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">showAlert() {
  this.alertCtrl.create({
    message: "Hello There",
    subHeader: "I'm a subheader"
  }).then(alert => alert.present());
}

// Or using async/await

async showAlert() {
  const alert = await this.alertCtrl.create({
    message: "Hello There",
    subHeader: "I'm a subheader"
  });

  await alert.present();
}

Local Notifications

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Plugins } from '@capacitor/core';
const { LocalNotifications } = Plugins;

LocalNotifications.schedule({
  notifications: [
    {
      title: "Title",
      body: "Body",
      id: 1,
      schedule: { at: new Date(Date.now() + 1000 * 5) },
      sound: null,
      attachments: null,
      actionTypeId: "",
      extra: null
    }
  ]
});

Custom Components

Create custom component

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="shell" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">$ ionic generate component components/Sample
> ng generate component components/Sample
CREATE src/app/components/sample/sample.component.scss (0 bytes)
CREATE src/app/components/sample/sample.component.html (25 bytes)
CREATE src/app/components/sample/sample.component.spec.ts (628 bytes)
CREATE src/app/components/sample/sample.component.ts (270 bytes)
UPDATE src/app/components/components.module.ts (621 bytes)
[OK] Generated component!
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="shell" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">$ ionic generate module components/Components --flat
> ng generate module components/Components --flat
CREATE src/app/components/components.module.ts (194 bytes)
[OK] Generated module!

Modify selector for component in app/components/sample/sample.component.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">@Component({
    selector: 'c-sample',
    templateUrl: './c-sample.component.html',
    styleUrls: [ './c-sample.component.scss' ]
})

Rename files for component

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">cd src/app/components/sample
mv sample.component.html c-sample.component.scss
mv sample.component.html c-sample.component.html
mv sample.component.html c-sample.component.spec.ts
mv sample.component.html c-sample.component.ts

Export created component in app/components/components.module.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';

import { SampleComponent } from './sample/sample.component';

@NgModule({
    imports: [ CommonModule, IonicModule.forRoot(), ],
    declarations: [ SampleComponent ],
    exports: [ SampleComponent ],
    entryComponents: [],
})
export class ComponentsModule { }

Add page to display the component

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">$ ionic generate page pages/Sample
> ng generate page pages/Sample
CREATE src/app/pages/sample/sample.module.ts (543 bytes)
CREATE src/app/pages/sample/sample.page.scss (0 bytes)
CREATE src/app/pages/sample/sample.page.html (133 bytes)
CREATE src/app/pages/sample/sample.page.spec.ts (691 bytes)
CREATE src/app/pages/sample/sample.page.ts (256 bytes)
UPDATE src/app/app-routing.module.ts (539 bytes)
[OK] Generated page!

Add custom component to new page sample.page.html

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="2" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-content padding>
    <c-sample></c-sample>
</ion-content>

Register components module in sample.module.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="1,7,8,15,17" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';

import { ComponentsModule } from 'src/app/components/components.module';
import { SamplePage } from './sample.page';

const routes: Routes = [ { path: '', component: SamplePage } ];

@NgModule({
    declarations: [SamplePage],
    imports: [
        CommonModule,  IonicModule,
        RouterModule.forChild(routes),
        ComponentsModule
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SamplePageModule {}

Check Routing in app-routing.modules.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="5" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home',   loadChildren: './pages/home/home.module#HomePageModule' },
  { path: 'list',   loadChildren: './pages/list/list.module#ListPageModule' },
  { path: 'sample', loadChildren: './pages/sample/sample.module#SamplePageModule' }
];

Add new page to sidemenu in app.components.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">  public appPages = [
    { title: 'Home', url: '/home', icon: 'home' },
    { title: 'List', url: '/list', icon: 'list' },
    { title: 'Sample Component', url: '/sample', icon: 'list' }
  ];

Directives

Pipes

HTML Elements

Access HTML Element from Page Class

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><div #box></div>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">@ViewChild('box', {static: false}) el_box:ElementRef;
box: any;

constructor() {
    this.box = this.el_box.nativeElement;
}

Grabbing Ionic Components with ViewChild

Let’s imagine we have a HomePage component that looks like this and we want to close the menu when an item is clicked.

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-menu>
</ion-menu>

Our goal is to access the ion-menu from the TypeScript code so we can call its API methods, like open() and close().

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="js" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Component, ViewChild } from '@angular/core';
import { Menu } from '@ionic/angular';

@Component(...)
export class HomePage {

  @ViewChild(Menu, {static: false})) menu: Menu;

  onDrag() {
    this.menu.close();
  }
}

Explanation:

{ static: false }

If you set static false, the component ALWAYS gets initialized after the view initialization in time for the ngAfterViewInit/ngAfterContentInit callback functions.

{ static: true}

If you set static true, the initialization will take place at the view initialization at ngOnInit

Shortcut: Use Template Variables

There’s actually a very convenient shortcut to using ViewChild in a component. We never have to leave the HTML by setting a template variable in Angular. In this example we reference the menu component with a hashtag and variable name #mymenu.

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-menu #mymenu>
  <ion-item (click)="mymenu.close()"></ion-item>

Grabbing Multiple Components with ViewChildren

You might also run into a situation where there are multiple components of the same type on the page, such as multiple FABs:

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-fab></ion-fab>
<ion-fab></ion-fab>
<ion-fab></ion-fab>

ViewChildren is almost the same, but it will grab all elements that match this component and return them as an Array.

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Component, ViewChildren } from '@angular/core';
import { Fab } from '@ionic/angular';

@Component(...)
export class HomePage {

  @ViewChildren(Fab, {static: false})) fabs: Fab[];


  closeFirst() {
    this.fabs[0].close();
  }
}

Now that you know about ViewChild, you should have no problem accessing the API methods found on Ionic’s web components.

Loops in HTML Elements

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ul>
   <li *ngFor="let number of [0,1,2,3,4]">
      {{number}}
   </li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ul>
  <li *ngFor='#key of [1,2]'>
    {{key}}
  </li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ul>
  <li *ngFor='#val of "0123".split("")'>{{val}}</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ul>
  <li *ngFor='#val of counter(5) ;#i= index'>{{i}}</li>
</ul>

export class AppComponent {
  demoNumber = 5 ;

  counter = Array;

  numberReturn(length){
    return new Array(length);
  }
}

Display Array

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="html" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-grid class="board">
  <ion-row *ngFor="let r of [0,1,2]">
    <ion-col col-4 class="cell" *ngFor="let c of [0,1,2]" (click)="handle(c+r*3)">
            {{squares[c+r*3]}}
    </ion-col>
  </ion-row>
</ion-grid>

Add function to Button click

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><ion-item (click)="onClick($event)">
<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">onClick(ev: any){
	this.log('onClick', 'event=' + ev);
}

Change CSS class on click

Add handler to html element

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title=""><a class="btn" (click)='toggleClass($event)'>
    <ion-icon class="icon" name="bluetooth"></ion-icon>
</a>

Import Render2 in page.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">import { Component, OnInit, Renderer2 } from '@angular/core';
...

constructor(private renderer: Renderer2) { }

Write handler to toggle class

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">toggleClass(event: any) {
    const classname = 'active';

    if (event.target.classList.contains(classname)) {
        this.renderer.removeClass(event.target, classname);
    } else {
        this.renderer.addClass(event.target, classname);
    }
}

Migrating to Ionic 4

Replace Http Module with HttpClient

Changes in app.module.ts

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">@NgModule({
    declarations: [AppComponent],
    entryComponents: [],
    imports: [
        ...
        HttpClientModule
        ...
    ],

ERROR: Unexpected end of JSON input while parsing near

<pre class="EnlighterJSRAW" data-enlighter-group="" data-enlighter-highlight="" data-enlighter-language="generic" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-theme="" data-enlighter-title="">npm cache clean --force
npm install -g @angular/cli
The Latest