ANGULAR 2021

The SPA living form

CC-BY-NC-4.0 / Mar. 2021 / Loïc TRUCHOT

L'approche ANGULAR

REACTIVE MODULES

  • Un framework complet pour les SPA
    • Components inspiré par l'architecture MVC
    • Router, multilang, SEO, HTTP, forms... baked in
    • CLI (webpack) / generator / seed le plus complet du marché
    • multi targets :
      • browser (app/element)
      • server (Universal)
      • mobile (PWA & Ionic/NativeScript)
      • OS (Electron)
    • 3 pierres angulaires:
      • TypeScript: Safe et future-proof JS 
      • RxJS: Reactive programming avec Observables
      • La modularité d'angular

Où Vit Angular?

Workshop

  • Installer le CLI d'angular
    • npm i -g @angular/cli
  • Créer un projet 
  • Trouver le titre "my-app" dans les sources de l'application
  • Trouver l'endroit ou ce titre est affiché dans un template HTML
  • Afficher "Angular > React" à la place du contenu actuel d'AppComponent
  • Ajouter ramda au projet, via NPM, et utiliser une des fonctions de ramda dans la partie "controller JS".
  • Afficher le résultat dans la fenêtre, sur le modèle de la propriété "title" du contrôleur

Bonus: Peut-on avoir des types typescript pour ramda ? comment ?

CLI

Arborescence d'un projet

  • .git et .gitignore pour la gestion de version
    e2e/karma/protractor pour les tests
    .angular-cli.json pour la configuration du CLI
    .editorconfig, tslint, tsconfig pour les règles de code
    package.json (+lock) et node_modules pour les dépendances
    README pour décrire le projet
    src pour les sources du projet

Sources d'un projet

  • index.html pour la racine HTML
    assets pour les fichiers statiques
    environments pour varier les configs
    favicon.ico pour l'apparence dans la barre de nav
    styles.css pour les styles globaux
    test.ts pour les tests
    tsconfig et typings pour aider à compiler
    polyfills.ts pour la rétrocompatibilité
    main.ts pour la racine de l'arbre (code)
    app pour le tronc et les branches (code)

NG MODULES

  • AppModule, module racine contenant
    • d'autres modules
      • des « services »
      • des « components » contenant
        • des « controllers »
        • des « templates » contenant  
          • des « directives »

Etes vous prets pour...

Pierre angulaire 1/3

angular BASICS

  • *ngIf
  •  
  • *ngFor
  •  
  • Interpolation {{ }}
  •  
  • Property binding [ ]
  •  
  • Safe navigation operator ?
<li *ngFor="let item of items; let i = index;">{{i}}. {{ item }}</li>
<div *ngIf="happy">:)</div>
<input type="range" [value]="rangeValue" />
<div>Mon chat s'appelle {{ catName }} </div>
{{ asyncData?.nom }}

Workshop

  • Donner le titre h1 "Liste de passager" à votre app component, via interpolation {{ }}
  • Préparer une collection de 5 passagers (nom, prénom, age: number, checkedIn: boolean)
  • Utiliser le pouvoir de TypeScript pour les rendre bien typé et safe
  • Utilisez *ngFor pour itérer sur vos passager dans une liste. Précéder leurs noms part un numéro.
  • Les passager "checkedIn" sont suivits d'un rond vert, les autres d'un rond rouge

Bonus: Vos passagers ont tous un visage, ils viennent tout droit de https://randomuser.me/

la liste de passagers 1/4

Custom components

et custom directives

  • générer de nouveau components:
    • ng generate component my-comp
  • <app-my-comp></app-my-comp> pour instancier
  • @Input() name; pour recevoir la propriété bindée [name]

Workshop

  • Vos passagers sont désormais instancié grâce au component Passager.

Bonus: La liste est elle même un Smart component, alors que App et Passenger sont dumbs

la liste de passagers 2/4

<app-passager 
  *ngFor="let passager of passagers; let i = index" 
  [infos]="passenger"
  [id]="index">
</app-passager>

event binding

  • 1 way binding = les valeurs sont réaffectées manuellement dans leurs classes
  • Les events sont déclarés dans le HTML, sans le "on" et entre ()
    • (click)="myMethod()"
    • (change)="changed($event.target.value)
    • ...
  • Que faire si l'événement vient d'un enfant ???
  • @Ouput () clicked= new EventEmitter();
  • et <child (clicked)="onClick($event)" />

Workshop

  • L'App affiche "CHECK IN EN COURS"
    • Cliquer sur le rond rouge le rend vert et vis-versa: le passager toggle son "checkedIn"

liste de passagers 3/4

Bonus: Si tous les passager sont checked in on affiche dans l'app:

  • EMBARQUEMENT IMMINENT...

NG natives Pipes

  • En Angular, on souhaite rester le plus MVC possible
  • Pas de logique dans le template (View), tout dans component (Controller)
  • Si une transformation complexe doit avoir lieu dans le template, on utilise des "pipes" |
  • Ces pipes | peuvent être chaînées !
  • Ces pipes | sont natives... ou custom !
<p>Mon anniversaire est le {{ birthday | date:"yMMMM" }} </p>
<div> Je voudrais bien des euros, par exemple: {{ money | currency | lowercase }} </div>
<span>Mais je veux pas {{ gift ? (gift | json ) : "rien"}}.</span>
<strong>Ce serais trop {{ "triste" | uppercase }} !</strong>

Workshop

  • Les passagers ont achetés un billet d'avion avec un prix très différents selon la période (price: number).
    • Afficher ce prix avec un pipe de currency en euro
  • Les passagers ont checked-in à une date précise (checkDate: number) - un timestamp
    • Afficher cette date formatée à la française

liste de passagers 4/4

Bonus: Lorsqu'on check-in, la date de check in change. elle disparait si on checkout

NG Router

  • Il est officiel
  • il est optionnel
import { RouterModule, Routes  } from '@angular/router';
const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'parts', component: PartsComponent },
  { 
    path: 'part/:id', 
    component: HeroListComponent },
  { 
    path: '', 
    redirectTo: '/home',
    pathMatch: 'full' 
  },
  { path: '**', component: Page404Component }
];
@NgModule({
  imports: [
    RouterModule.forRoot(
      appRoutes
    )
  ]
})
export class AppModule {}
  • Il est imbricable
  • il est paramétrable

La directive qui marque l'emplacement du router dans l'App est <router-outlet>

<router-outlet></router-outlet>

Workshop

  • Produire une application pour une agence de voyage
  • Choisir 4 destination et trouver une photo pour chaque
  • Il y a une home avec une liste des 6 destinations dont deux inconnues
  • Chaque destination est une route vers un component
  • Les destinations inconnues tombent en 404 avec une belle page d'erreur

Bonus: Il n'y a plus qu'une seule route pour  les destinations, mais une partie de l'url est le param de destination

un beau voyage

Quelques belles routes:

  • home
  • destinations
    • italie
    • turquie
    • togo
    • laos
  • 404

Cycle de vie du COMPOSANT

  • Faut-il fetcher dans le constructor ?
    • ngOnInit () {}
  • Y a-t-il un "destructor" ?
    • ngOnDestroy () {}

 

Ces méthodes ne font pas partie du décorateur @Component... il faut les "implémenter" dans la classe (typescript)

export class Mood implements OnInit {
  happy: boolean = true;
  ngOnInit() { 
    setInterval(this.toggleHappiness, 3000) 
  }
  toggleHappiness() {
    this.happy = !this.happy 
  }
}

Et il y en a beaucoup:

  • ngOnChanges()
  • ngDoCheck()
  • ngAfterContentInit()
  • ngAfterContentChecked()
  • ngAfterViewInit()
  • ...

hTTP client

import { 
  HttpClientModule 
} from '@angular/common/http';

@NgModule({
  imports: [
    ...,
    HttpClientModule,
    ...
  ]
})
export class AppModule {}

Ni Fetch, ni Axios, juste Angular et moi

  • Un des nombreux module angular
  • Optionnel mais officiel
  • Retourne des Observables
  • Liés à la pipe "async"
import { HttpClient } from '@angular/common/http';
export class Mood implements OnInit {
  creatures: Observable<any>;
  constructor(private http: HttpClient) { }
  ngOnInit() { 
    this.creature = this.http.get("assets/creatures.json");
  }
}
<div *ngFor="let creature of (creatures | async)">{{ creature.name }}</div>

Workshop

  • Demander au formateur une API ouverte diffusant des data récente
  • OU utilisez la votre !
  • Fetchez les dans un ngOnInit, avec HttpClient et affichez les grâce à | async

Ajax

Bonus: Trouver une dépendance angular pour faire des beaux graphiques. Afficher quelques données de votre API sous form graphique

NG serviceS

  • Un helper pour décongestionner les controllers
  • Un endroit pour stocker la data partagée, idéalement miroir du server (autrement dit un Model)

ng generate service livres

@Component({...})
export class BibliothequeComponent {
    constructor(private _livresService: LivresService) {
    }
    logLivres () { console.log(this.livresService.getLivres()); }
}
import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root',
})
export class LivresService {
  private _livres = ["Naruto", "Platon"];
  getLivres () { return _livres; }

}

Workshop

Bonus 2: Faire un bouton déclanchant 3 sons

Toujours plus fort (featuring daft punk)

Bonus: Faire des boutons stop/start/restart

Bonus 3: Effets disco + mot cliqué qui grossi et fade out

[
  'work it', 'make it', 'do it', 'makes us',
  'harder', 'better', 'faster', 'stronger',
  'more than', 'hour', 'our', 'never',
  'ever', 'after', 'work is', 'over'
]
<iframe
  src="silence.mp3"
  allow="autoplay"
  style="width:0; height:0; position:absolute; left:-1px"
></iframe>
  • Le clavier ET la souris peuvent déclencher chaque son
  • Le son "song-instrumental" se lance lorsque App se lance

↓ Alternative

Workshop

  • Faire une app permettant d'apprendre les mots de d'une autre langue, par catégorie
  • Par exemple:
    • politesse: bonjour, aurevoir, merci, s'il vous plaît
    • animaux: chien, chat, poulet, vache
  • Chaque catégorie est une route dynamique de l'app
  • Les data sont en JSON dans les assets et sont fetchées
  • Il y a une image représentant chaque concept
  • C'est beau (utilisez flex, bootstrap ou tailwindcss)

Apprendre les langues

Bonus: Votre app permet d'apprendre 3 langues: on sélectionne sa langue maternelle, et on apprend une autre qu'on choisie

THANK'S EVERYONE
It's finally done ! See you soon

Angular 2020 - The all-in-one SPA

By Loïc TRUCHOT

Angular 2020 - The all-in-one SPA

Introduction à Angular, en français et sans compromis.

  • 413