Angular est un framework frontend survitaminé permettant de réaliser simplement des interfaces web riches et dynamiques.
Plus qu’une bibliothèque, la solution Angular propose un cadriciel complent s’articulant autour de solides patrons de conceptions.
Si son nom est commun à celui de son grand-frère Angular.JS, cette nouvelle version n’a a beaucoup mûrie est facilite grandement la vie des développeurs web.
Exemple : Numéro de version 1. 2. 3
Exemple de classe Typescript
import {Injectable} from "@angular/core";
import {UserSegment} from "../model/user-segment";
import {Story} from "../../story/model/story";
import {Recorder} from "./recorder";
import {RecordFileManager} from "./record-file-manager.service";
import {UserSegmentService} from "./user-segment.service";
@Injectable()
/**
* Record Service
* Abstraction of story recording: the service manages the data story
* and the files persistence.
*/
export class RecordService {
private _recorder: Recorder;
private _data: Array<Blob>;
constructor(
private userSegmentService: UserSegmentService,
private recordFileManager: RecordFileManager
) {
this._recorder = new Recorder();
}
public get data() {
return this.data;
}
public async newSession(story:Story) {
let currentUserSegment: UserSegment = await this.userSegmentService.create(story.segments[0]);
this._data = [];
}
// ...
}
<my-id></my-id>
<my-id attrib="smthg"></my-id
<audio></audio>
Exemple
<audio controls>
<source src="horse.ogg" type="audio/ogg">
<source src="horse.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
Dans l’exemple ci-dessus, le composant audio
a pour identifiant audio
. La déclaration de son attribut controls
active la présence des boutons de contrôle.
Les sous-composants source
décrivent les liens vers les fichiers audios.
Dans le cadre d’une application Angular, un composant est la synthèse entre :
L’affichage d’une page HTML avec Angular est réalisé de manière dynamique.
Cela signifie que le DOM est construit en respectant les instructions décrites par les directives.
Une directive est définie par le décorateur @Directive
. Un composant décrit par @Component
est une directive avec un template.
Il existe deux types de directives : structurelles et attributs
Elles modifient la structure d’un template HTML en ajoutant, retirant, modifiant des éléments du DOM.
Par exemple :
<li *ngFor="let story of stories"></li>
<story-detail *ngIf="selectedStory"></story-detail>
*ngFor
génère autant d’éléments <li>
qu’il y a d’objets dans le tableau stories
*ngIf
affichera la composant <story-detail>
uniquement quand la valeur de selectedStory
existeraCes directives sont dynamiques. Par défaut, toute modification des valeurs référentes (stories
et selectedStory
) entraîne une reconstruction du DOM et un rafraîchissement de la vue.
Elles modifient l’apparence ou le comportement d’éléments existant. Elles ressemblent à des attributs HTML.
Une directive attribut ne correspond pas aux attributs déjà existants d’un composant. Au contraire, elle permet d’ajouter des mécaniques supplémentaires.
Les directives ngSwitch
, ngStyle
et ngClass
modifient l’aspect d’éléments du DOM et des composants.
Ce type de directive est reconnaissable par la présence des marqueurs de liaison de données : []
|& ()
Par exemple :
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special</div>
Exemple
import {Segment} from "./chapter";
export class Story {
private _title:string;
private _chapters:Array<Chapter>;
constructor(title?: string, chapters?: Array<Chapter>) {
this._title = title;
this._chapters = [];
}
get title(): string {
return this._title;
}
set title(value: string) {
this._title = value;
}
// ...
Les interfaces Typescript permettent de décrire le type des attributs d’un Objet javascript. Son rôle principal est la description.
À la différence d’une classe, l’interface ne propose par de comportement pour les objets.
Une interface peut être utilisée pour décrire un objet javascript construit dynamiquement ou obtenu par déserialisation par exemple.
Exemple
import {iChapter} from "./ichapter";
export interface iStory {
title: string;
chapters: Array<iChapter>;
}
price | currency:'USD':true
Affiche le prix 42.33 sous la forme $42.33
cf. doc.
Un composant web est la synthèse
import { Component } from '@angular/core';
@Component({
selector: 'pause-btn',
templateUrl: 'pause-btn.html',
styleUrl: 'pause-btn.scss'
})
export class PauseBtn {
protected _paused: boolean;
constructor() {
this._paused = false;
}
get paused():boolean {
return this._paused;
}
pause():boolean {
this._paused = true;
return this.paused;
}
}
Un template HTML décrit la structure du DOM du composant. Il peut être composé des balises HTML standards, de composants, directives et il peut utiliser des pipes pour modifier l’affichage de certaines données.
Ainsi, un template HTML Angular est lié de manière dynamique à des variables et des fonctions issues du contrôleur du composant auquel il est associé.
Pour cela, Angular propose des expressions, encadrées par des {{ myExpression }}
. Ces expressions permettent d’injecter de manière dynamique le contenu d’une variable au sein d’une balise HTML.
Par exemple, <h1>{{title | uppercase}}</h1>
le contenu de la variable title
décrite dans le contrôleur Typescript associé, sera insérée dans la balise <h1>
et sera mise en majuscule automatiquement.
Toute modification de la variable title
entraînera le rafraîchissement de la vue.
Template contrôleur
Pour associer la valeur d’un attribut HTML à une variable ou une fonction, Angular propose la syntaxe suivante.
<img [src]="getImageSrc()" />
L’attribut src
de la balise <img>
est alors associé au résultat de la fonction getImageSrc()
.
Ce résultat est dynamique : si la fonction retourne à l’instant t+1 un résultat différent de l’instant t, alors la valeur de l’attribut src
est modifié.
Ainsi, grâce à cette liaison de donnée, la source de l’image peut être modifié dynamiquement.
Template contrôleur
Pour réaliser une liaison de données depuis le template vers le contrôleur, Angular propose l’utilisation des parenthèses ()
.
<img src="..." (click)="imgAction()"/>
Lorsque l’utilisateur cliquera sur l’image, il entraînera le déclenchement de la fonction imgAction()
décrite par le contrôleur typescript.
<a [href]="myVar">link</a>
<a (click)="myFunction()>link<./a>
<input [(ngModel)]="name" />
Les feuilles de style d’une application Angular respectent la même notion de construction hiérarchique.
Le composant racine peut posséder une feuille de style initiale définissant un style qui sera utilisé pour lui et tous ses sous-composants.
Chaque composant d’un niveau hiérarchique n hérite des guides de style de ses composants parents n-m pour tout m > 1. Cependant, le style qu’il définira à son niveau n ne sera accessible que pour lui et ses sous-composants n+m pour tout m >= 1.
Exemple
button-red {
background-color: color($colors, red);
div {
background-color: yellow;
}
}
D’après Angular, un service est un composant tiers contenant du code métier. Cette définition floue laisse libre au développeur l’interprétation du terme service.
Angular propose ainsi au développeur une mécanique d’injection de dépendance hiérarchique. Un service peut être injecté grâce à ce système. On identifiera ainsi un service injectable avec le décorateur @Injectable()
.
L’injection de services tiers se fait par le constructeur. Lorsque notre service est instancié par l’application, ses dépendances sont résolues.
@Injectable()
export class StoryService {
constructor(
public logger: Logger
) {}
}
La classe StoryService
est ici considérée comme injectable.
Le constructeur de la classe décrit la dépendance du service Logger. La précision public est une facilité syntaxique pour décrire que ce paramètre de construction est également un attribut de la classe, accessible par this.logger
.
À l’instanciation de la classe StoryService, la dépendance sur service Logger récupérera l’instance associé à ce type le plus proche.
Le terme plus proche désigne le processus suivant.
En considérant l’inclusion par modules, chaque service appartient à un module, le module racine d’une application étant le tout premier niveau.
Chaque module peut inclure plusieurs modules et ce récursivement. Ainsi, lors de l’injection de dépendance, le système d’injection cherche à chaque niveau hiérarchique de module si une intance de Logger a été précisée, en commençant par le niveau du module injecteur et en remontant niveau par niveau les modules parents.
Lorsqu’une instance du service a été trouvé à un étae, celle-ci est associée à l’attribut du service instancié, logger
ici. Le cas contraire, le système remonte d’un étage supplémentaire, jusqu’à trouver une instance.
Un module désigne un ensemble indépendant de fonctionnalités d’une application. Un module peut contenir des composants, services, pipes, styles, templates et d’autres modules.
Une application Angular est un module, qui peut inclure d’autres sous-modules.
Les modules permettent d’organiser une application en la structurant en briques indépendantes facilement réutilisables et testables.
Une application Angular est ainsi l’articulation d’un ensemble de modules, dépendants les uns des autres selon une structure hiérarchique.
Un module est décrit par le décorateur @NgModule()
. Celui-ci possède plusieurs options de configuration. Voir la documentation de NgModule
@NgModule({
declarations: [ // Importation des pages
MyApp,
AboutPage,
ContactPage,
HomePage
],
imports: [ // Imports d'autres modules
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp], //
entryComponents: [ // Component factory, est nécessaire en cas d'eager loading
MyApp,
AboutPage,
ContactPage,
HomePage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
Sur cette exemple, on distingue plusieurs options de configuration qui permettent de paramétrer un module.
declarations
Déclare une liste de directives / pipes qui appartiennent au module. Cela ne les instancie pas.
providers
Définit un ensemble d’objets injectables qui seront utilisables par l’injecteur de ce module. Cette option sera utilisée par l’injecteur pour créer les instances de chaque service mentionné et génèrera un singleton propre au module.
exports
Chaque module peut exporter ce qu’il contient : directives, composants, pipes, services. Lorsque ce module sera importé par un module tiers, seuls les éléments exposés ici seront disponibles.
imports
L’options permet de spécifier une liste de modules qui seront importés afin d’importer les éléments publiques des modules (directives, composants, pipes, services).
bootstrap
Définit les composants qui devront être amorcés (bootstrappés) lorsque ce module le sera. Les composants mentionnés ici seront automatiquement ajoutés à entryComponents
.
entryComponents
Définit une liste de composants qui devront être compilés quand le module sera défini.
L’injection d’une dépendance de service recherche l’instance de service cible la plus proche.
Cette instanciation peut être réalisée par l’injecteur au niveau du module, d’un composant ou d’un service.
Comme décrit plus haut, l’option providers
du décorateur @NgModule()
permet de déclarer l’instanciation d’un service de le rendre disponible pour tous les éléments du modules (services, pipes, composants).
Il est également possible de déclarer l’instanciation d’un service dans un composant, service, pipe. Ces décorateurs possèdent également une option providers
.
Un service instancié au niveau de ces éléments aura la priorité la plus importante lorsque l’injecteur résoudra les dépendances.
Cette présentation succinte présente les bases d’Angular. La documentation officielle est bien illustrée et présente plusieurs catégories bien construites :