Préface

Le but de ce document est d'aider à concevoir des applications angular organisée et qualitative. Pour atteindre ce but, ce document définit des principles directeurs, une organisation de fichiers, des bonnes pratiques de développement et de testing.

Concepts de programmation

Programmation réactive

Imperative programming versus Declarative programming

Il est important de saisir la différence entre ces 2 styles de programmation.
La programmation impérative est un style de programmation dans lequel on définit explicitement les étapes que le programme doit suivre pour obtenir le résultat souhaité. En d'autres termes, on décrit comment faire les choses.
D'autre part, la programmation déclarative est un style de programmation dans lequel on décrit ce qu'on veut/quoi faire. Au lieu de définir explicitement chaque étape, on déclare nos intentions. Tout code déclaratif est donc une abstraction du code impératif.

Analogie en cuisine

Si on faisait une analogie en cuisine cela pourrait donner ceci avec le style impératif:

  • 1. Prenez un bol et un fouet.
  • 2. Prenez 2 oeufs et 125gr de farine et 250cl de lait et du sucre.
  • 3. Craquez les oeufs dans un bol.
  • 4. Versez la farine dans le bol.
  • 5. Incorporez le lait lentement en agitant le fouet jusqu'au ce que la pâte soit fluide.
  • 6. Ajoutez le sucre et remuer.
  • 7. Recouvrez le bol.
  • 8. Placez le bol au frigo 1h.

La même analogie en style déclaratif:

  • 1.Préparez les ustensiles.
  • 2.Préparez les ingrédients (pour 2 personnes).
  • 3.Mélangez les ingrédients.
  • 4.Laissez reposer la pâte.
Note: On pourrait même aller plus loin et avoir ceci: Préparez de la pâte à crêpes (pour 2 personnes) Toutefois si on faisait une abstraction de toutes les étapes, cela illustrerait moins bien la différence entre les 2 styles de programmation.

La programmation déclarative

Le code réactif est une variante du code déclaratif. On utilise le style déclaratif pour réagir aux changements de données au fil du temps.

Code Versus: JS sample

                    // Imperative
                    let numbers = [1, 2, 3];
                    let doubledNumbers = [];

                    for (let i = 0; i < numbers.length; i++) {
                    doubledNumbers[i] = numbers[i] * 2;
                    }

                    // Declarative/Reactive
                    let numbers$ = of([1, 2, 3]);
                    let doubledNumbers$ = numbers$.pipe(map(numbers => numbers.map(n => n * 2)));
                    

Code Versus: Angular sample

                    import { Component } from '@angular/core';
                    import { DataService } from './data.service';
                    import { Observable } from 'rxjs';

                    @Component({
                    selector: 'app-root',
                    template: `
                    <h2>Imperative</h2>
                    <ul>
                    <li *ngFor="let item of data">{{ item }}</li>
                    </ul>

                    <h2>Reactive</h2>
                    <ul>
                    <li *ngFor="let item of data$ | async">{{ item }}</li>
                    </ul>
                    `,
                    })
                    export class AppComponent {
                    data: string[];
                    data$: Observable;

                    constructor(private dataService: DataService) {
                    // Imperative approach
                    this.dataService.getData().subscribe((data) => {
                    this.data = data;
                    });

                    // Reactive approach
                    this.data$ = this.dataService.getData();
                    }
                    }
                    

Dans l'approche impérative, on s'abonne manuellement à l'Observable et on met à jour la propriété data lorsque de nouvelles données sont reçues.
Dans l'approche réactive, on utilise le pipe async pour s'abonner à l'observable data$ et mettre automatiquement à jour la vue lorsque de nouvelles données sont émises.
Les deux approches obtiennent le même résultat, mais l'approche réactive rend le code plus lisible et tout en écrivant moins de code.

Documentation The reactive development paradigm
Documentation Thinking Reactively: Most Difficult | Mike Pearson
Documentation RxJS Declarative Pattern in Angular
Documentation Declarative vs imperative
Documentation [github]: How to handle errors REACTIVELY with the async pipe

Best practices

Reactive programming: handling errors

// home.page.ts
import { Component } from '@angular/core';
import { of } from 'rxjs';
import { catchError, ignoreElements } from 'rxjs/operators';
import { UserService } from '../shared/data-access/user/user.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
})
export class HomePage {
  user$ = this.userService.getUser();
  userError$ = this.user$.pipe(
    ignoreElements(),
    catchError((err) => of(err))
  );

  constructor(public userService: UserService) {}
}
    // home.page.html
    <ng-container *ngIf="{user: user$ | async, userError: userError$ | async} as vm">
        <app-card *ngIf="!vm.userError && vm.user as user; else loading">
            <app-card-content>
                <p>{{ user }}</p>
            </app-card-content>
        </app-card>
        <app-error *ngIf="vm.userError as error"> {{ error }} </app-error>

        <ng-template #loading>
            <app *ngIf="!vm.userError">
                <app-card-content>
                    <app-skeleton-text animated></app-skeleton-text
                </app-card-content>
            </app>
        </ng-template>
    </ng-container>

Enum versus Types

Documentation Angular best practices
Documentation These ARE the Angular tips you are looking for | John Papa

Les formulaires

Les formulaires sont un élément essentiel dans toute application web et constitue le pillier centrale des applications de gestion. Il est donc important de les passer en revue et de se mettre d'accord sur comment aborder ce point au sein du code.