Pourquoi Migrer de Angular.js vers Angular ?
L'Angular 2 (ou simplement Angular) est sorti en 2016 et a depuis connu plusieurs mises à jour importantes, incluant Angular 4, Angular 5, Angular 6, Angular 7, Angular 8, Angular 9, Angular 10 et la plus récente Angular 11. Ces dernières versions ont apporté de nombreux améliorations et nouvelles fonctionnalités qui rendent le framework plus performant, plus facile à utiliser et plus adapté aux projets modernes.
Le migration d'Angular.js vers Angular n'est pas une tâche légère car les deux frameworks diffèrent significativement en termes de conception, de performance et de facilité d'utilisation. Cependant, la migration peut offrir plusieurs avantages :
- Mise à jour continue : Angular est actuellement soutenu par Google et le projet Open Source AngularJS n'est plus maintenu.
- Performance améliorée : Angular utilise des concepts comme le JIT (Just-In-Time) compiler qui permet une meilleure performance que le rendu côté client de AngularJS.
- Meilleure gestion du code : L'utilisation d'un système de module et de structures de données plus performantes rend le code plus organisé et facile à maintenir.
Un cas concret serait l'entreprise qui utilise actuellement Angular.js pour développer des applications web et qui souhaitent profiter des dernières fonctionnalités et améliorations offertes par Angular. La migration permettrait d'utiliser les derniers outils et bibliothèques, ce qui faciliterait le développement et la maintenance.
Prerequis
Pour migrer de Angular.js vers Angular, vous aurez besoin des éléments suivants :
- Node.js : Version 10.13 ou supérieure
- npm (Node Package Manager)
- Un éditeur de code moderne comme Visual Studio Code
- Connaissance de base d'Angular.js
Concepts fondamentaux
1. Modules et Composants
Dans AngularJS, nous avions des controllers et des directives. Dans Angular, les concepts sont des Modules, des Composants, des Services et des Observables.
Schema mental :
Module (App Module) -> Component -> Template -> Service -> Observable
Bloc de code fonctionnel :
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<h1>Bonjour Angular!</h1>`
})
export class AppComponent {
}
2. Services
Les services dans Angular sont des classes qui contiennent le code métier et sont accessibles à travers l'injecteur de dépendances.
Schema mental :
Service -> Injectable -> Injection
Bloc de code fonctionnel :
// task.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class TaskService {
getTasks(): string[] {
return ['Faire les courses', 'Nettoyer la maison'];
}
}
3. Templates et Data Binding
Les templates en Angular sont des fichiers HTML qui utilisent le système de data binding pour afficher les données.
Schema mental :
Template -> Interpolation -> Property Binding -> Event Binding
Bloc de code fonctionnel :
<!-- app.component.html -->
<h1>title</h1>
<button (click)="onButtonClick()">Cliquez-moi</button>
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
title = 'Bienvenue';
onButtonClick() {
alert('Bouton cliqué!');
}
}
4. Routing
Angular fournit un système de routing pour naviguer entre différentes vues.
Schema mental :
Module -> Routes -> RouterModule -> RouterLink -> RouterOutlet
Bloc de code fonctionnel :
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
AboutComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
5. Observables et Async Pipe
Les observables sont des objets qui représentent une séquence de valeurs émises au fil du temps. L'async pipe permet d'utiliser les observables directement dans le template.
Schema mental :
Observable -> Subscribe -> Async Pipe
Bloc de code fonctionnel :
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { interval } from 'rxjs';
@Component({
selector: 'app-root',
template: `<p>time | async</p>`
})
export class AppComponent implements OnInit {
time = interval(1000);
}
Mise en pratique : projet fil rouge
Nous allons construire un gestionnaire de tâches simple pour illustrer la migration d'Angular.js vers Angular.
Étape 1 : Création du Projet
ng new task-manager --routing
cd task-manager
Étape 2 : Création des Composants
Créons un composant task-list pour afficher la liste des tâches et un composant add-task pour ajouter de nouvelles tâches.
ng generate component task-list
ng generate component add-task
Étape 3 : Structure du Projet
Le projet aura une structure similaire à celle-ci :
task-manager/
├── src/
│ ├── app/
│ │ ├── app.component.html
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── routing.module.ts
│ │ ├── add-task/
│ │ │ ├── add-task.component.html
│ │ │ ├── add-task.component.spec.ts
│ │ │ ├── add-task.component.ts
│ │ │ └── add-task.component.css
│ │ └── task-list/
│ │ ├── task-list.component.html
│ │ ├── task-list.component.spec.ts
│ │ ├── task-list.component.ts
│ │ └── task-list.component.css
├── angular.json
├── package.json
└── README.md
Étape 4 : Implémentation du Composant add-task
// add-task.component.ts
import { Component } from '@angular/core';
import { TaskService } from '../task.service';
@Component({
selector: 'app-add-task',
templateUrl: './add-task.component.html',
styleUrls: ['./add-task.component.css']
})
export class AddTaskComponent {
newTask = '';
constructor(private taskService: TaskService) {}
addTask() {
this.taskService.addTask(this.newTask);
this.newTask = '';
}
}
html
<!-- add-task.component.html -->
<div>
<input type="text" [(ngModel)]="newTask" placeholder="Nouvelle tâche">
<button (click)="addTask()">Ajouter</button>
</div>
Étape 5 : Implémentation du Composant task-list
// task-list.component.ts
import { Component, OnInit } from '@angular/core';
import { TaskService } from '../task.service';
@Component({
selector: 'app-task-list',
templateUrl: './task-list.component.html',
styleUrls: ['./task-list.component.css']
})
export class TaskListComponent implements OnInit {
tasks: string[] = [];
constructor(private taskService: TaskService) {}
ngOnInit() {
this.tasks = this.taskService.getTasks();
}
}
html
<!-- task-list.component.html -->
<ul>
<li *ngFor="let task of tasks">task</li>
</ul>
Étape 6 : Configuration du Routing
Ajoutons le routing pour afficher les composants add-task et task-list.
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AddTaskComponent } from './add-task/add-task.component';
import { TaskListComponent } from './task-list/task-list.component';
const routes: Routes = [
{ path: '', component: AddTaskComponent },
{ path: 'list', component: TaskListComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AddTaskComponent } from './add-task/add-task.component';
import { TaskListComponent } from './task-list/task-list.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
AddTaskComponent,
TaskListComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Étape 7 : Ajout des Styles
Ajoutez un peu de style pour rendre le gestionnaire de tâches plus présentable.
/* add-task.component.css */
input, button {
margin-right: 10px;
}
ul {
list-style-type: none;
padding: 0;
}
css
/* task-list.component.css */
li {
border-bottom: 1px solid #ccc;
padding: 5px 0;
}
Étape 8 : Test du Projet
Exécutez le projet pour vérifier que tout fonctionne comme prévu.
ng serve
Accédez à http://localhost:4200 et vous devriez voir une interface de gestionnaire de tâches simple avec un champ pour ajouter des tâches et une liste pour afficher les tâches ajoutées.
Erreurs frequentes et debugging
1. Erreur : Cannot find module './task.service'
Code incorrect :
// app.module.ts
import { TaskService } from './task.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [TaskService],
bootstrap: [AppComponent]
})
export class AppModule { }
Code correct :
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TaskService } from './task.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [TaskService],
bootstrap: [AppComponent]
})
export class AppModule { }
2. Erreur : Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'.
Code incorrect :
<!-- add-task.component.html -->
<input type="text" [(ngModel)]="newTask" placeholder="Nouvelle tâche">
<button (click)="addTask()">Ajouter</button>
Code correct :
Assurez-vous d'avoir importé FormsModule dans votre module.
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AddTaskComponent } from './add-task/add-task.component';
import { TaskListComponent } from './task-list/task-list.component';
import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
AddTaskComponent,
TaskListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
3. Erreur : TypeError: Cannot read property 'subscribe' of undefined
Code incorrect :
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { interval } from 'rxjs';
@Component({
selector: 'app-root',
template: `<p>time | async</p>`
})
export class AppComponent implements OnInit {
time = interval(1000);
}
Code correct :
Assurez-vous d'avoir importé interval depuis rxjs.
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { interval } from 'rxjs';
@Component({
selector: 'app-root',
template: `<p>time | async</p>`
})
export class AppComponent implements OnInit {
time = interval(1000);
}
Pour aller plus loin
1. Comprendre les pipes personnalisés
Les pipes sont des fonctionnalités puissantes pour transformer les données dans le template. Vous pouvez créer des pipes personnalisés pour formater vos données de manière spécifique.
Liens :
2. Utiliser les guards pour la navigation
Les guards sont des mécanismes qui permettent d'ajouter une logique de contrôle avant que l'utilisateur ne puisse accéder à certaines routes.
Liens :
3. Intégrer des bibliothèques tierces
Angular offre une grande flexibilité et peut être intégré à de nombreuses bibliothèques tierces pour ajouter des fonctionnalités spécifiques.
Liens :
Défi pratique
Créez une application de chat simple avec des fonctionnalités de connexion, d'envoi et de réception de messages. Utilisez les composants, services et routing d'Angular pour construire l'application.
Instructions :
- Créez un service
chat.service.tspour gérer la communication entre le client et le serveur. - Créez un composant
login.component.tspour permettre aux utilisateurs de se connecter. - Créez un composant
message-list.component.tspour afficher les messages reçus. - Configurez le routing pour naviguer entre la page de connexion et la page des messages.