16. September 2019
Ionic | Cookbook
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>
Navigate Programmatically
<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');
}
}
Navigate to Dynamic URLS
<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;
}
}
Passing parameter in link
<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 });
}
Passing parameter in routerlink directive
<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 Navigation
is 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