Enhance Web Development

Angular 2

 

Le panorama

Le panorama

  • Les principaux concepts
  • Démarrer une application
  • Et plus en détail !?

Les principaux concepts

  • Module
  • Composant
  • Metadata
  • Template
  • Data Binding
  • Service
  • Directives
  • Dependency Injec

Comment démarrer une application

  • Importer le module bootstrap
  • Importer votre composant
  • Importer vos dépendances
  • Appeler la méthode bootstrap en lui donnant le composant et les dépendances
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {AppComponent} from './app.component'; 
 
bootstrap(AppComponent, [
    ROUTER_PROVIDERS 
]);

Et plus en détail

  • Utilise la syntaxe ES6
  • Angular 2 utilise les modules pour leurs code
  • Les modules exportent des bouts de code que d'autres modules peuvent importer
  • TIPS : Garder les modules léger et spécialisés

Module

// In home.component.ts
export class HomeComponent { }

// In app.component.ts
import {HomeComponent} from './home/home.component';

Module

  • Les composants sont des classes ES6
  • Les providers sont injectés dans le constructeur
  • Déclaration explicite des providers & directives
  • Possibilité d'intercepter tous les évènements
  • Les propriétés et méthodes du composant sont disponibles dans la vue

Composant

export class HomeComponent implements OnInit{
    title: string = 'Home Page'; 
    body: string = 'This is the about home body';
    message: string; 
 
    constructor(private _stateService: StateService) { } 
 
    ngOnInit() { 
        this.message = this._stateService.getMessage();
    } 

    updateMessage(m: string): void { 
        this._stateService.setMessage(m);
    } 
}

Composant

  • Décore une classe ES6
  • On peut attacher des metadatas avec les annotations/décorateurs de TypeScript (ES7?)
  • Les décorateurs sont des fonctions
  • Le plus utilisé : @Component()
    • prend un objet de config avec le sélecteur, le template, les providers, les directives, les pipes et les styles

Metadata

@Component({
    selector: 'home', 
    templateUrl: 'app/home/home.component.html'
}) 
export class HomeComponent{ }

Metadata @Component()

  • Un template est écrit en HTML et définit le rendu d'un composant
  • Les templates comprennent des "data-binding", d'autres composants et directives
  • Angular 2 utilise les évènements DOM natifs
  • Angular 2 utilise le shadow DOM

Template

Template

Template

@Component({ 
    selector: 'experiment', 
    templateUrl: './experiment.detail.component.html',
    styles: [` 
        .experiment { 
            cursor: pointer; 
            outline: 1px lightgray solid;  padding: 5px; 
            margin: 5px; 
        }
    `] 
})

Template

@Component({ 
    selector: 'experiment', 
    template: ` 
        <div class="experiment" (click)="doExperiment()"> 
        <h3>{{ experiment.name }}</h3> 
        <p>{{ experiment.description }}</p>
        <p><strong>{{experiment.completed}}</strong></p> 
        </div> 
    `, 
    styles: [` 
        .experiment { 
            cursor: pointer; 
            outline: 1px lightgray solid;  padding: 5px; 
            margin: 5px; 
        }
    `] 
})
  • Permet de créer un échange de données entre le composant et le template
  • Inclut : interpolation, le binding de propriété, d'évènement et le two-way binding (propriété + évènement)

Data-binding

Data-binding

Data-binding

<h1>{{title}}</h1> 
<p>{{body}}</p> 
<hr/> 
<experiment *ngFor="#experiment of experiments" 
            [experiment]="experiment"></experiment>
<hr/> 
<div>
    <h2 class="text-error">Experiments: {{message}}</h2>
    <form class="form-inline"> 
        <input type="text" 
            [(ngModel)]="message" placeholder="Message"> 
        <button type="submit" class="btn" (click)="updateMessage(message)">
            Update Message 
        </button>
    </form> 
</div>
  • Un service est une classe ES6
  • Un service s'occupe d'une chose uniquement
  • Embarque toute la logique business du composant
  • Classe ES6 décorée avec @Injectable si on veut l'injecteur dans no service

Service

Service

import {Injectable} from 'angular2/core';
import {Experiment} from './experiment.model';   

@Injectable() 
export class ExperimentsService { 
    private experiments: Experiment[] = []; 
 
    getExperiments(): Experiment[] { 
        return this.experiments;
    }; 
}
  • Une directive est une classe ES6
  • Décorée avec @Directive()
  • Un composant est une directive avec un template !
  • Directives disponibles nativement dans Angular 2

Directive

Directive

import { Directive, ElementRef } from 'angular2/core';   

@Directive({ 
    selector: '[femBlinker]'
}) 
 
export class FemBlinker { 
    constructor(element: ElementRef) {
        let interval = setInterval(() => { 
            let color = element.nativeElement.style.color;
            element.nativeElement.style.color =
                (color === '' || color === 'black') ? 'red' : 'black';
        }, 300); 
 
        setTimeout(() => { 
            clearInterval(interval);
        }, 10000); 
    }
}
  • Permet de récuperer l'instance d'une class par son nom (Singleton)
  • Permet d'initialiser qu'une seule fois les services
  • Pour utiliser DI pour un service, il faut l'enregistrer en tant que provider : au bootstrap de l'application ou dans les metadata d'un composant

Dependency Injection

Dependency Injection

// experiments.service.ts
import {Injectable} from 'angular2/core';   
@Injectable() 
export class ExperimentsService { }

// experiments.component.ts
import {ExperimentsService} from '../common/ experiments.service'; 
import {StateService} from '../common/state.service';   
export class ExperimentsComponent { 
    constructor( 
        private _stateService: StateService, 
        private _experimentsService: ExperimentsService
    ) {} 
}
  • Regarde les changement dans le modèle de donnée pour recompiler le DOM
  • Les changements sont : les évènements, les requêtes XHR et les timers
  • Chaque composant possède son détecteur de changement
  • On peut personnaliser le ChangeDetectionStrategy.OnPush pour utiliser des objets immutable ou observables
  • On peut dire à Angular d'écouter un composant particulier en injectang ChangeDetectorRef et en appelant markForCheck() dans le composant

Détection de changement

Détection de changement

export interface Item {
    id: number; 
    name: string;
    description: string; 
};   
export interface AppStore {
    items: Item[];
    selectedItem: Item; 
};
  • Angular utilise Jasmine (framework de test)
  • On doit :
    • Importer les dépendances depuis @angular/testing
    • Importer les classes à tester
    • Inclure les providers en important beforeEachProviders
    • Injecter les providers en appelant inject([arrayOfProviders], (providerAliases) => {})

Les tests

Les tests

import { describe, it, expect } from 'angular2/testing';   
import { AppComponent } from './app.component';   
describe('AppComponent', () => {
    it('should be a function', () => {
        expect(typeof AppComponent).toBe('function');
    }); 
});
  •  Inclure tous les fichiers liés à un composant dans le même dossier
  • CIA pour Class Import Anotate
  • Utiliser des templates écrit dans le fichier JS
  • Garde le template simple et court
  • Déporter la logique métier du composant vers un provider
  • Découper vos composants complexe
  • Toujours réfléchir à comment les données vont être changer (impact sur le Change Detection)

Les conseils d'architecture

Défi

  • Récupérer et faire tourner l'application
  • Identifier les artefacts Angular
  • Ajouter une propriété dans un composant et l'afficher dans la vue
  • Ajouter une propriété dans le service stateService et l'utiliser dans un composant
  • BONUS : Créer une interface pour typer votre propriété

Linalis - 03 - Le panorama

By Benjamin LONGEARET

Linalis - 03 - Le panorama

  • 832