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 :
sudo 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. Dans la version actuelle d’Angular, les composants sont par défaut en Standalone. Donc c’est l’option Standalone que nous choisirons. En Standalone, lorsque vos composants utilisent des classes, des méthodes, des fonctions définies ailleurs (par exemple, le routerLink), vous devez les importer dans l’annotation @Component qui précède vos classes. C’est ce que vous avez fait dans les séances de développement web. Les ngModules sont une autre technique pour réaliser ces imports mais elle est obsolète. 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.
À 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 puis, en bas à gauche ou à droite, sur l’icône indiquée dans le cercle rouge de l’image ci-dessous. Vous pouvez alors 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.
Créez un projet forum-ionic
pour le frontend en ionic de votre forum.
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 Ionic 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 première 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>
Supprimez le répertoire contenant la page home et créez une nouvelle page login. Faites en sorte que la route par défaut pointe, non plus sur home, mais sur login. Supprimez dans les routes tout ce qui fait encore référence à home.
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, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import {provideHttpClient} from '@angular/common/http';
import {provideAnimations} from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
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, withPreloading, PreloadAllModules } from '@angular/router';
import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
import {provideHttpClient} from "@angular/common/http";
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes, withPreloading(PreloadAllModules)),
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
.
Démarrez votre serveur backend. Créez deux services message et auth et recopiez dedans tout le code que vous aviez écrit pour ces services dans votre forum « Angular ». N’oubliez pas d’inclure le provideHttpClient().
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. l’URL 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. |
Copiez-collez dans les parties TypeScript et HTML (dans la zone <ion-content></ion-content>) de votre page login tout ce que vous aviez écrit pour ce composant dans votre forum « Angular ».
Créez une nouvelle page pour la page cours, qui permettra d’afficher la liste des cours (pour pouvoir faire un maximum de copiers/collers, il est important de donner aux pages que vous créez dans Ionic les mêmes noms que les composants correspondants de votre forum Angular). Pour l’instant, laissez cette page telle qu’elle est créée par Ionic.
Testez que vous pouvez bien vous logguer. Pour l’instant, ne vous préoccupez pas du style de la page.
Ionic est livré avec plein de composants prêts à l’emploi, qui vont vous simplifier la vie. Ils se trouvent sur l’URL :
https://ionicframework.com/docs/components
Par exemple, Ionic propose des composants spécifiques pour les listes, les inputs, les checkboxes, les date pickers, etc.
Pour créer des listes, on peut utiliser les classiques balises ol, ul, li. Mais, en faisant cela, on n’a pas le look 'n feel des applications sur smartphone. Pour obtenir ce dernier, il faut utiliser les balises ion-list et ion-item spécifiques de Ionic :
https://ionicframework.com/docs/api/list
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>Blank</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-list inset="true">
<ion-item>{{info.nom}}</ion-item>
<ion-item>nombre : {{info.nb}}</ion-item>
</ion-list>
</ion-content>
Pour que cela fonctionne, il vous faudra importer IonInput dans votre
fichier
login.page.ts
. Pour cela, vous avez deux options :
l’importer de @ionic/angular/standalone
,
l’importer de @ionic/angular
.
Le second item importera IonItem en utilisant le système de modules ngModule. Or, vous avez créé votre projet en standalone. Il faudra donc sélectionner la première des deux options ci-dessus.
import {IonList, IonItem} from '@ionic/angular/standalone';
Voici le résultat obtenu dans le navigateur :
Dans le <ion-header></ion-header> en haut de la page, ajoutez l’attribut color="primary" à la balise <ion-toolbar>.
Remplacez les balises <input> par des balises <ion-input> (cf. l’URL https://ionicframework.com/docs/api/input).
Utilisez l’attribut placeholder des <ion-input> afin de demander à l’utilisateur de saisir son login ou password: cela permet d’éviter d’avoir, au dessus du <ion-input>, un label demandant la même chose, d’où un gain de place sur l’écran (de petite taille du smartphone).
Maintenant faites en sorte que les balises <ion-input> soient les éléments (<ion-item></ion-item>) d’une <ion-list>. Pour voir comment fonctionnent ces listes, vous pouvez vous reporter à la documentation de Ionic :
Transformez le bouton de connexion en <ion-button> et placez-le dessous de la liste. Vous pourrez utiliser l’attribut color="primary" pour lui donner une apparence plus sympathique.