Angular2 couplé avec spring boot

 

Qui n’a pas entendu parler de la nouvelle version du célèbre framework Angular JS!? Et oui Angular2 est maintenant disponible après quelques mois d’attente! Cette nouvelle version est plus aboutie selon moi. Comme le recommande la team Angular, l’utilisation de Typescript est vraiment un plus surtout pour un développeur comme moi qui a l’habitude du Java et des langages objet. Côté performance, Angular2 est plus rapide que son prédécesseur. Il y a plusieurs analyse à ce sujet disponible sur le web. La création de directives est simplifiée. Personnellement, sur la première version d’Angular, je trouve que la création de directives est un peu fastidieuse. Côté architecture, on retrouve un peu la même logique avec les « module component », « module service » et le fameux « injector ». Je reviendrai plus en détails sur ces concepts dans un prochain tuto.

Entrons dans le vif du sujet!

Je me suis amusé à faire le très bon tuto disponible sur le site angular.io en y ajoutant Spring Boot (hé oui on ne se refait pas…) et quelques fonctionnalités.

Tout d’abord vous pouvez récupérer les sources ici sur mon github. Le tuto représente le « Tour of heroes », vous trouverez plus de détails ici.

Une fois l’application lancée, en vous rendant à l’adresse http://localhost:9000/, vous devriez voir ceci :

 

tour-of-heros

En cliquant sur un des items de la liste, le détail devrait s’afficher en bas de la liste comme ceci :

 

tour-of-heroes-details

OK c’est cool tout ça, mais comment arrive-t-on à ce résultat me direz-vous… On y arrive ;-).

Voyons comment sont organisées les sources du projet. Il s’agit d’un projet maven donc Java avec par dessus Spring Boot qui permet de mettre en place une application opérationnelle très rapidement.

 

angular2-layout

 

Dans le dossier src/main/resources/public/, on retrouve les sources de notre application pour la partie Angular2. On a le dossier app/ qui contient nos composants Typescript. Le dossier node_modules/ contient les modules node.js dont dépend Angular2. Il y a plusieurs autres fichiers notamment de configuration de l’application. Le fichier qui nous intéresse plus particulièrement ici est index.html qui est le point d’entrée. En effet, ce dernier constitue la « home page » de notre application.

A l’intérieur de la balise <body>, on y trouve le tag suivant :

 

<my-app>Loading...</my-app>

 

Cet élément est une directive qui sera traduit par Angular2 vers le contenu HTML définit dans le composant responsable.

Hein? Oui contrairement à la première version d’Angular ou l’on parle de contrôleurs ici on parle de composants. Pour chaque directive, un composant doit être définit. Le composant en charge ici se trouve dans le fichier app.component.ts et voici ce qu’on peut y lire :

 

import {Component} from '@angular/core';
import {Hero} from './hero';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroListComponent } from './hero-list.component';

@Component({
 selector: 'my-app',
 template: 
 <h1>{{title}}</h1>
 <h2>My Heroes</h2>
 <hero-list (emitHero)="handleEvent($event)"></hero-list>
 <my-hero-detail [hero]="selectedHero"></my-hero-detail>`,
 directives: [HeroDetailComponent, HeroListComponent]
})
export class AppComponent {
 public title:string = 'Tour of heroes';
 public selectedHero:Hero;
 handleEvent(hero:Hero) { this.selectedHero = hero;}
 }

 

On y définit le « selector » comprenez balise html. Le « template » est le code html qui sera affiché une fois le « selector » compilé. Au niveau du template, on retrouve d’autres directives <hero-list> et <my-hero-detail>. Chacune de ces directives a donc un composant associé dans lequel on retrouve toute la logique « métier ».

Avant d’aller explorer les autres composants, essayons de comprendre ce que veut dire le code html du template.

 

<h1>{{title}}</h1>
<h2>My Heroes</h2>
<hero-list (emitHero)="handleEvent($event)"></hero-list>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>

 

Alors… On commence par afficher le titre de l’application grâce à la variable publique title. Ensuite on affiche « My Heroes ». Bon rien d’extraordinaire pour l’instant. Après ça, la directive <hero-list> permet d’afficher une liste d’héros. Mais pas que! Il y a la gestion de l’évènement emitHero qui sera délégué à la méthode handleEvent. On y revient juste après. Suit la balise <my-hero-detail> qui affichera les détails pour un héros donné. Le héros en question est renseigné grâce aux propriétés hero et selectedHero. Je vais détailler le fonctionnement dans un instant ne vous inquiétez pas.

Commençons par une explication un peu globale du fonctionnement de l’application. Donc comme je disais au départ on affiche une liste de héros avec en dessous le détail pour un héros donné. Ce héros sera celui sur lequel on a cliqué.  On introduit donc 2 nouveaux composants : hero-detail.component.ts et hero-list.component.ts. 

Le composant hero-list est en charge d’afficher la liste des héros et de gérer le click sur un héros dans la liste.

 

import { Component, Input, Output, EventEmitter} from '@angular/core';
import {Hero} from './hero';

@Component({
 selector: 'hero-list',
 template: `
 <ul class="heroes">
 <li *ngFor="let hero of heroes" 
 [class.selected]="hero === selectedHero"
 (click)="onSelect(hero)">
 <span class="badge">{{hero.id}}</span> {{hero.name}}
 </li>
 </ul>
 `
})
export class HeroListComponent {
 @Input()
 selectedHero: Hero;

 @Output()
 emitHero = new EventEmitter<Hero>();

 public heroes = HEROES;

 onSelect(hero: Hero) { this.emitHero.emit(hero); }
}

const HEROES: Hero[] = [
 { id: 1, name: 'Mr. Nice' },
 { id: 2, name: 'Narco' },
 { id: 3, name: 'Bombasto' },
 { id: 4, name: 'Celeritas' },
 { id: 5, name: 'Magneta' },
 { id: 6, name: 'RubberMan' },
 { id: 7, name: 'Dynama' },
 { id: 8, name: 'Dr IQ' },
 { id: 9, name: 'Magma' },
 { id: 10, name: 'Tornado' }
 ];

 

Lorsque l’on clique sur un héros, le composant appelle sa méthode onSelect qui déclenche l’évènement emitHero en lui passant le héros concerné. L’évènement emitHero sera propagé à l’extérieur soit au composant parent. L’annotation @Output couplée au type EventEmitter permet de spécifier le fait que l’on veuille propager un évènement. Cet évènement est effectivement récupéré par le composant parent app qui à son tour appelle la méthode handleEvent. Dans cette méthode le composant app renseigne la valeur de sa propriété selectedHero :

 

handleEvent(hero:Hero) { this.selectedHero = hero;}

 

Cette propriété est ensuite utilisé par le composant hero-detail afin d’afficher les détails :

 

import { Component, Input } from '@angular/core';
import {Hero} from './hero';

@Component({
 selector: 'my-hero-detail',
 template: `
 <div *ngIf="hero">
 <h2>{{hero.name}} details!</h2>
 <div><label>id: </label>{{hero.id}}</div>
 <label>name: </label>
 <input [(ngModel)]="hero.name" placeholder="name">
 </div>`
})
export class HeroDetailComponent {
 @Input()
 hero: Hero;
}

 

Grace à l’annotation @Input, on peut spécifier que la valeur de la propriété sera récupérée de l’extérieur, en l’occurence ici elle est renseignée par le composant parent app.

Je ne rentre pas dans les détails concernant la syntaxe d’Angular. Je pense consacrer un article à ce sujet qui sera prochainement disponible. La documentation officielle offre de bonnes explications avec des exemples à l’appui.

Le mot de la fin :

Angular (version 1 et 2) est un framework que j’ai découvert il y quelques années et cette nouvelle mouture est un réel succès à mes yeux. Approche objet, notions de composants, utilisation de TypeScript, etc… J’espère que ce tuto vous a donné envie de vous y plonger un peu plus. Il s’agit juste d’une mise en bouche mais imaginez une architecture avec Angular en front et un langage comme du Java côté backend avec des webservices rest! Magnifique non?!…