
Existing member? Log in and continue learning

See if you like it, start the course for free!

Unlock full course by purchasing a membership
Adding Ionic to an Angular Application
Adding Ionic to an Angular Application
We’ve spent a little while working with a standard Angular application generated using the Angular CLI. We’ve also already created an Ionic application using the Ionic CLI. This is great because it sets up everything for us out of the box, and we can just start building!
But… it does muddy the waters a bit. If our application already includes Ionic by default then it is kind of hard to tell what is “Ionic” and what is “Angular”. We’ve let the Ionic CLI handle the jump from an “Angular” application to an “Ionic/Angular” application for us.
This is most certainly what you should do when building Ionic applications: use the Ionic CLI to generate the application for you. However, it is useful as a learning exercise to start off with a standard Angular application generated with the Angular CLI and add Ionic to it manually. Not only will this show us what Ionic changes about a standard Angular application, it is also going to give us some experience setting up and configuring a third party library in Angular.
It is also useful to demonstrate that all of the Angular knowledge you are gaining by learning Ionic is also applicable more broadly to Angular applications in general.
So, that is exactly what we are going to do in this lesson!
Generate an application with the Angular CLI
First, let’s generate a new Angular application with the Angular CLI:
ng new angular-to-ionic
You can use the following configurations:
✔ Do you want to create a 'zoneless' application without zone.js (Developer Preview)? No✔ Which stylesheet format would you like to use? Sass (SCSS) [ https://sass-lang.com/documentation/syntax#scss ]✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
Install Ionic Dependencies
Now we will need to install Ionic itself, which we can do by installing the following two packages:
npm install @ionic/angular ionicons
Add Ionic config file
Although we will not be making particular use of it right now, Ionic projects come with a configuration file to configure various things. Let’s set that up now.
{ "name": "angular-to-ionic", "integrations": {}, "type": "angular-standalone"}
Provide Ionic to the Application
One of the most important configutations is making sure that we update our
app/app.config.ts
file to:
- Add
provideIonicAngular
to theproviders
- Use the
IonicRouteStrategy
- Use
PreloadAllModules
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection,} from '@angular/core';import { RouteReuseStrategy, provideRouter, withPreloading, PreloadAllModules,} from '@angular/router';import { IonicRouteStrategy, provideIonicAngular,} from '@ionic/angular/standalone';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = { providers: [ { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, provideIonicAngular(), provideBrowserGlobalErrorListeners(), provideZonelessChangeDetection(), provideRouter(routes, withPreloading(PreloadAllModules)), ],};
In the code above, we are saying we want to provide the RouteReuseStrategy
token, but we want to use the class IonicRouteStrategy
for that token.
That means that wherever the RouteReuseStrategy
token is used, it will
actually use an instance of IonicRouteStrategy
.
Route reuse strategies are a much more advanced topic, and you don’t really ever need to consider it too much. The key idea is that, by default, whenever we navigate between components in Angular, Angular will destroy the component that was just navigated away from. If we later come back to that route the component will be recreated again. This might not always be what you want, and Ionic defines some more specific rules around when components should be created and destroyed.
This is where Ionic’s lifecycle hooks like ionViewWillEnter
and
ionViewWillLeave
come into play. These are like Angular’s ngOnInit
lifecycle
hook, except that they run at times related to the Ionic Page
Lifecycle. We will not often
use Ionic’s specific hooks, but consider a situation where you are running some
logic using Angular’s ngOnInit
hook. This only runs when the component is
first created. If, according to Ionic’s route reuse strategy, some component is
not destroyed when we navigate away from it, then the ngOnInit
logic will not
run when we navigate back to it. It is rarer, but in situations like this we
might need to explicitly run some logic inside of a hook like ionViewWillEnter
which will run every time we navigate to that page, regardless of whether it
has already been created or not.
Update index.html
You will also find that an Ionic project has a few mobile specific changes made
to the index.html
file. Compare the index.html
file of a standard Angular
project:
<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>AngularToIonic</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"></head><body> <app-root></app-root></body></html>
to what we need to update our index.html
file to for Ionic.
<!DOCTYPE html><html lang="en">
<head> <meta charset="utf-8" /> <title>AngularToIonic</title>
<base href="/" />
<meta name="color-scheme" content="light dark" /> <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" />
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- add to homescreen for ios --> <meta name="mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /></head>
<body> <app-root></app-root></body>
</html>
Add Ionic CSS imports
Ionic also comes with some additional styling configuration.
/* Core CSS required for Ionic components to work properly */@import "@ionic/angular/css/core.css";
/* Basic CSS for apps built with Ionic */@import "@ionic/angular/css/normalize.css";@import "@ionic/angular/css/structure.css";@import "@ionic/angular/css/typography.css";@import "@ionic/angular/css/display.css";
/* Optional CSS utils that can be commented out */@import "@ionic/angular/css/padding.css";@import "@ionic/angular/css/float-elements.css";@import "@ionic/angular/css/text-alignment.css";@import "@ionic/angular/css/text-transformation.css";@import "@ionic/angular/css/flex-utils.css";
/** * Ionic Dark Mode * ----------------------------------------------------- * For more info, please see: * https://ionicframework.com/docs/theming/dark-mode */
/* @import "@ionic/angular/css/palettes/dark.always.css"; *//* @import "@ionic/angular/css/palettes/dark.class.css"; */@import '@ionic/angular/css/palettes/dark.system.css';
Change the Router
<ion-app> <ion-router-outlet /></ion-app>
import { Component } from '@angular/core';import { IonApp, IonRouterOutlet } from '@ionic/angular/standalone';
@Component({ selector: 'app-root', imports: [IonApp, IonRouterOutlet], templateUrl: './app.html', styleUrl: './app.scss',})export class App { title = 'angular-to-ionic';}
This is an important one, and there are two things going on here. One is that
we are using the <ion-router-outlet>
instead of the default Angular
<router-outlet>
. By default, Angular will apply mobile style transition
animations when switching between views, and using Ionic’s version of the router
outlet is what will enable this. We also surround our entire application in the
<ion-app>
component which is important for styling.
Try out some components
That should be all we need to do for a basic set up. Usually we would serve an
Ionic application with the Ionic CLI using ionic serve
but since we are just
using a normal Angular application here we can instead just do ng serve
.
If you do that you should see you have a working, but blank, application. That’s no fun though, so let’s set up a few of Ionic’s components so that we can actually see something.
To get the full sense of why using Ionic’s own router is useful, let’s set up two pages that the router outlet will route to: a home page and a detail page so that we can actually see some navigation occurring between two pages.
import { Component } from '@angular/core';import { RouterLink } from '@angular/router';import { IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonList, IonNote, IonTitle, IonToolbar,} from '@ionic/angular/standalone';import { addIcons } from 'ionicons';import { logoIonic } from 'ionicons/icons';
@Component({ selector: 'app-home', template: ` <ion-header> <ion-toolbar> <ion-title>My app</ion-title> </ion-toolbar> </ion-header>
<ion-content> <ion-header collapse="condense"> <ion-toolbar> <ion-title size="large">My app</ion-title> </ion-toolbar> </ion-header> <ion-list> @for (item of items; track $index) { <ion-item [button]="true" routerLink="/home/1"> <ion-icon slot="start" name="logo-ionic" size="large"></ion-icon> <ion-label>Hello</ion-label> <ion-note slot="end">6</ion-note> </ion-item> } </ion-list> </ion-content> `, imports: [ IonHeader, IonToolbar, IonContent, IonTitle, IonList, IonItem, IonLabel, IonIcon, IonNote, RouterLink, ],})export default class HomeComponent { items = new Array(50).fill(1);
constructor() { addIcons({ logoIonic }); }}
We are using a bunch of Ionic components here to create a standard mobile
layout. Notice that since we are using standalone
components, we just import
whatever we want to use into the component and add it to the imports
array.
import { Routes } from '@angular/router';
export const routes: Routes = [ { path: 'home', loadComponent: () => import('./home/home.component'), }, { path: '', pathMatch: 'full', redirectTo: 'home', },];
Now if we serve the application we can immediately see some of Ionic’s magic come into play here with this condensed header. If I view this on an Android device I’m going to get the Android styling, but if I view it on an iOS device I am going to get this iOS design where we have a larger title on the page, and then as we scroll down that title sort of morphs into the top toolbar. You can easily see/test the iOS/Android specific styling by emulating difference devices using Chrome DevTools.
This gives us a bit of a sense of what Ionic’s UI components look like, but now let’s set up our second page so that we can see what a transition using the Ionic router outlet looks like.
import { Component } from '@angular/core';import { IonBackButton, IonButtons, IonContent, IonHeader, IonInputOtp, IonTitle, IonToolbar,} from '@ionic/angular/standalone';
@Component({ selector: 'app-detail', template: ` <ion-header> <ion-toolbar> <ion-buttons slot="start"> <ion-back-button /> </ion-buttons> <ion-title>Detail page</ion-title> </ion-toolbar> </ion-header>
<ion-content> <ion-input-otp> Didn't get a code? <a href="#">Resend the code</a> </ion-input-otp> </ion-content> `, imports: [ IonHeader, IonToolbar, IonContent, IonTitle, IonButtons, IonBackButton, IonInputOtp, ],})export default class DetailComponent {}
import { Routes } from '@angular/router';
export const routes: Routes = [ { path: 'home', loadComponent: () => import('./home/home.component'), }, { path: 'home/:id', loadComponent: () => import('./detail/detail.component'), }, { path: '', pathMatch: 'full', redirectTo: 'home', },];
Now if you serve the application you will see that you can click on one of the list items and the detail page will animate into view just as it typically would for an iOS/Android application. Again, the animation will adapt appropriately for whatever platform it is running on.
Add Capacitor
The other key part that the Ionic CLI typically sets up for us is the integration with Capacitor which is what allows us to build our applications natively for iOS and Android and it also allows us to integrate various native capabilities (e.g. things like the Camera, Files, GPS, and so on).
We can also just manually add Capacitor to a standard Angular application by running a single command.
ionic integrations enable capacitor --quiet -- my-app io.ionic.starter
Now we can do everything we need with Capacitor (we will get more into Capacitor later).
Recap
That’s it! We have now converted a standard Angular application into an Ionic application that is almost identical to one created by the Ionic CLI.