La figure ci-dessous illustre bien l’idée générale de Ionic.
Sur sa partie gauche, on voit les logos d’Angular, React et Vue. En effet, Ionic s’appuie sur ces frameworks pour générer ses applications. Plus exactement, c’en est une surcouche. On voit également les logos d’Android et d’Apple : grâce à Ionic, on peut produire des applications pour ces deux OS.
La partie droite de la figure détaille cette architecture : Ionic est, certes, une surcouche d’Angular, React et Vue, mais ce framework propose également ses propres composants, qui sont adaptés au look “n feel d’Android et d’iOS. Pour s’adapter à ces derniers, notamment pour exploiter les composants des smartphones (appareil photo, GPS, etc.), Ionic s’appuie sur Capacitor. Cela lui permet de produire des applications natives Android, iOS, ou encore des PWA (Progressive Web Applications).
Une fois Ionic installé via la commande :
npm install -g @ionic/cli
vous pouvez créer un nouveau projet monprojet, via la commande suivante :
ionic start monprojet
Ionic va alors vous demander de choisir sur quel framework s’appuyer (Angular, React ou Vue). Dans le cadre de ce module, nous utilisons Angular. Ensuite, on doit choisir un squelette pour le projet. Blank sera notre option par défaut. Puis Ionic vous demandera quel système de modules Angular vous souhaitez utiliser : ngModules ou Standalone. Vous avez vu en TP que, dans la version actuelle d’Angular, les composants sont en Standalone. Donc c’est l’option que nous choisirons. Enfin, la dernière question qui vous sera posée est si vous souhaitez créer ou non un compte Ionic. Ce n’est pas nécessaire.
Notez que, par défaut, l’installation inclut Capacitor, qui nous servira à exploiter les capacités des smartphones sur lesquels nous allons déployer nos applications Ionic.
Le projet ainsi créé se présente avec les fichiers comme indiqué ci-dessous :
On note que la structure est similaire à celle d’Angular. Quelques fichiers sont toutefois différents :
le fichier src/app/styles.scss devient src/app/global.scss ;
il y a un répertoire theme dans lequel on peut mettre des indications de style ;
il y a un répertoire environnements, qui peut exister également en Angular mais seulement si on le génère (ng generate environments) ;
il y a un fichier de configuration de capacitor.
A l’exception de ces quelques différences, vous retrouverez à peu près les mêmes fichiers que dans Angular.
Afin de visualiser le projet sur le navigateur, il suffit d’exécuter la commande :
ionic serve
Celle-ci va exécuter un ng serve mais en lui spécifiant le port 8100, qui est le port par défaut de Ionic (celui d’Angular est 4200).
Vous pouvez alors visualiser votre projet dans votre navigateur. Bien évidemment, La page web que vous observerez n’est pas tout à fait identique à celle visible sur un smartphone car les dimensions de votre navigateur diffèrent de celles d’un smartphone. Pour pallier cela, cliquez droit pour inspecter votre page. en bas à gauche, comme indiqué dans le cercle rouge de l’image ci-dessous, vous pouvez demander à votre navigateur de passer en mode « visualisation smartphone ». L’ellipse rouge en haut vous indique le type de smartphone sélectionné. Vous pouvez évidemment le modifier.
Contrairement à Angular, en Ionic, on différencie le composant app des pages de l’application.
Comme dans Angular, le point d’entrée de l’application est le fichier index.html qui contient essentiellement une seule balise : <app-root></app-root>.
Le fichier app.component.html est légèrement différent de celui d’Angular :
<ion-app>
<ion-router-outlet></ion-router-outlet>
</ion-app>
Toute application doit en effet être incluse dans un <ion-app></ion-app>. Le fichier app.component.ts est similaire à celui d’Angular.
Ce composant n’a pas vraiment vocation à être une page, comme il l’est dans Angular. En effet, ce qui prévaut, ici, c’est son fichier de routes, qui est, par défaut, plus sophistiqué :
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'home',
loadComponent: () => import('./home/home.page').then((m) => m.HomePage),
},
{
path: '',
redirectTo: 'home',
pathMatch: 'full',
},
];
En effet, on ne se contente pas d’indiquer le « composant » à afficher pour une route donnée, on utilise loadComponent, qui permet de charger de manière lazy et asynchrone les pages dont on a besoin. Cela permet à l’application de se charger plus vite et offre donc une meilleure expérience utilisateur, notamment quand le réseau n’est pas très rapide.
Notez la deuxième route : quand on crée un projet Ionic, une page par défaut nommée home est créée. Contrairement à Angular, qui ne différencie pas les composants qui représentent une page de ceux qui sont des éléments à l’intérieur d’une page, Ionic fait cette différence : une page est une page, un composant est un composant.
Pour générer une nouvelle page, on doit utiliser la commande :
ionic generate page ma_nouvelle_page
Ionic génère alors les mêmes fichiers qu’Angular aurait généré pour un composant, mais avec le suffixe page :
ma_nouvelle_page.page.html
ma_nouvelle_page.page.scss
ma_nouvelle_page.page.spec.ts
ma_nouvelle_page.page.ts
Concernant la partie TypeScript, peu de choses à dire : c’est exactement comme les composants en Angular :
import { Component } from '@angular/core';
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
standalone: true,
imports: [IonHeader, IonToolbar, IonTitle, IonContent],
})
export class HomePage {
constructor() {}
}
La partie HTML est plus intéressante. Elle est composée de 3 parties :
dans un <ion-header></ion-header>, on indique ce que contient le haut de la page. Même si on doit scroller, cette partie apparaîtra toujours en haut de l’écran. C’est typiquement ici que l’on placera une barre de navigation.
dans un <ion-content></ion-content>, on indique le contenu scrollable de la page. C’est l’élément principal de celle-ci.
dans un <ion-footer></ion-footer>, on indique ce que contiendra la partie non scrollable en bas de l’écran. Celle-ci est optionnelle. C’est pour cela que vous ne la voyez pas dans le fichier home.page.html.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Blank
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Blank</ion-title>
</ion-toolbar>
</ion-header>
<div id="container">
<strong>Ready to create an app?</strong>
<p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
</div>
</ion-content>
Comme en Angular, on peut créer des services via la commande :
ionic generate service mon_service
Voici un exemple basique de service, comme vu en Angular :
import { Injectable } from '@angular/core';
import {Observable, of} from "rxjs";
export interface MyInfo {
nom : string;
nb : number;
}
@Injectable({
providedIn: 'root'
})
export class MonServiceService {
constructor() { }
getInfos() : Observable<MyInfo> {
return of({nom: "toto", nb: 3});
}
}
On peut l’utiliser simplement dans un composant ou une page :
import { Component, OnInit } from '@angular/core';
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
import {MonServiceService, MyInfo} from "../mon-service.service";
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
standalone: true,
imports: [IonHeader, IonToolbar, IonTitle, IonContent],
})
export class HomePage implements OnInit {
info!: MyInfo;
constructor(private mon_service: MonServiceService) {}
ngOnInit() {
this.mon_service.getInfos().subscribe(res => {this.info = res;});
}
}
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Blank
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<div id="container">
<p>Info : {{info.nom}} : {{info.nb}}</p>
</div>
</ion-content>
En général, les données proviennent d’un backend auquel on accède via un client Http. Convertir le service pour cela est aisé :
import { Injectable } from '@angular/core';
import {Observable, of} from "rxjs";
import {HttpClient} from "@angular/common/http";
export interface MyInfo {
nom : string;
nb : number;
}
@Injectable({
providedIn: 'root'
})
export class MonServiceService {
constructor(private http: HttpClient) { }
getInfos() : Observable<MyInfo> {
return this.http.get<MyInfo>('http://127.0.0.1/xmobile_cours/info.php');
}
}
En revanche, il faut ajouter le module HttpClient à l’application. En Angular, cela se fait en rajoutant une instruction dans le fichier app.config.ts :
import { ApplicationConfig } from '@angular/core';
import {provideRouter} from '@angular/router';
import { routes } from './app.routes';
import {provideAnimations} from "@angular/platform-browser/animations";
import {provideHttpClient} from "@angular/common/http";
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideAnimations()
]
};
En Ionic, la technique est similaire mais le nom du fichier est différent : il s’agit du fichier main.ts :
import { bootstrapApplication } from '@angular/platform-browser';
import { RouteReuseStrategy, provideRouter } from '@angular/router';
import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
import { environment } from './environments/environment';
import {provideHttpClient} from "@angular/common/http";
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes),
provideHttpClient()
],
});
Notez que le fichier main.ts existe également en Angular et qu’il contient précisément le même code, à ceci près qu’en Angular, le 2ème argument de la fonction bootstrapApplication est l’objet appConfig du fichier app.config.ts alors qu’en Ionic, on indique le contenu de cet objet directement dans le fichier main.ts.
Dans la section précédente, nous avons vu comment la page home pouvait exploiter dans la méthode ngOnInit() un service Http afin de charger les données dont elle a besoin. Dans votre application, vous aurez probablement plusieurs pages et vous pouvez revenir plusieurs fois sur la page home. Si vous exécutez un console.log() à l’intérieur de ngOnInit(), vous pourrez observer qu’un seul affichage apparaîtra dans la console, quel que soit le nombre de fois où vous revenez sur la page home.
Ionic prévoit différentes méthodes afin d’initialiser/de mettre à jour une page quand on l’affiche pour la première fois ou bien quand on y revient ultérieurement, (cf. https://ionicframework.com/docs/angular/lifecycle) :
méthode | Exécution |
---|---|
ngOnInit | Exécutée quand on crée l'instance de la page pour la première fois. Utile pour charger des données à partir de services, qui n'ont pas besoin d'être rafraichis ultérieurement. |
ionViewWillEnter | Exécutée quand le router va débuter l'animation permettant d'afficher la page. Utile pour mettre à jour les données juste avant de revenir sur la page |
ionViewDidEnter | Exécutée quand le router vient de terminer l'animation permettant d'afficher la page, c'est-à-dire juste avant qu'on puisse l'utiliser. |
ionViewWillLeave | Exécutée quand le router va débuter l'animation permettant d'afficher une autre page. |
ionViewDidLeave | Exécutée quand le router a terminé l'animation permettant d'afficher une autre page. |