Table de multiplication

Objectif

  • Apprendre à concevoir une application front gérant plusieurs pages, via des routes distincts à l’image d’une application web classique.

  • Apprendre à paramétrer un composant : passage de valeurs à un composant via son sélecteur HTML (via ses attributs)

L’idée de l’application

On souhaite concevoir une application web qui affiche une table de multiplication (1 à 10), selon une valeur soumise par l’utilisateur.

Une table de multiplication affiche dans les lignes et colonnes le résultat de la multiplication des petits nombres entiers naturels. Le terme usité du Moyenge au XVIe siècle était « livret ».

Le système de numération décimale de position permet d’effectuer la multiplication de deux nombres quelconques à l’aide de la seule connaissance des produits des nombres de 0 à 9 entre eux.

C’est à l’école primaire que s’effectue l’apprentissage des tables qui récapitulent tous ces produits.

La tradition a longtemps exigé la connaissance des tables de multiplication portant jusqu’à 12 ou 13 au lieu de 9. (source : wikipedia)

L’analyse

On concevra une application qui présentera deux pages : une page présentant une table de multiplication

maquette table de 1

et une autre page présentant les tables de multiplication.

maquette les tables de multiplication

Outre les 2 composants de type page, l’application comportera deux autres composants : TableMultiplication, qui aura pour rôle de présenter une table de multiplication et TablesMultiplication pour représenter les tables de multiplication.

Ces composants seront paramétrés.

Initialisation de l’application (CLI)

ng new table-mult-app --routing --defaults

Les dépendances

On décide de s’appuyer sur bootstrap pour la mise en forme CSS.

Installation des modules bootstrap

(racine du projet)$ npm install --save bootstrap
(racine du projet)$ npm install --save bootstrap-icons

L’option save indique que le paquetage s’installe uniquement dans le projet et non globalement.

Pour nous simplifier le travail de présentation, nous utiliserons le module bootstrap pour angular (https://ng-bootstrap.github.io/#/home)

ng add @ng-bootstrap/ng-bootstrap

Ajouter les dépendances dans angular.json :

[...]
"styles": [
   "node_modules/bootstrap/dist/css/bootstrap.min.css",
   "node_modules/bootstrap-icons/font/bootstrap-icons.css",
   "src/styles.css"
 ],
 "scripts": [
   "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
 ]
[...]
Sous Visual Code, on gagnerait à installer l’extension IntelliSense for CSS class names in HTML pour profiter de la complétion des classes CSS.

Les composants

L’application proposera plusieurs "pages", qui devront présenter la même structure.

Nous allons donc factoriser le modèle de présentation par une entête et un pied de page, chacun étant représenté par un composant.

Création du composant Header

ng g component component/header

Nous prendrons un template classique de la documentation bootstrap.

/src/app/compoment/header/header.component.html
<nav class="navbar navbar-expand-xl navbar-light bg-light">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">
        <h1>MyApp</h1>
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
              aria-expanded="false">
              Dropdown
            </a>
            <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
              <li><a class="dropdown-item" href="#">Action</a></li>
              <li><a class="dropdown-item" href="#">Another action</a></li>
              <li>
                <hr class="dropdown-divider">
              </li>
              <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
          </li>
          <li class="nav-item">
            <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
          </li>
        </ul>
        <form class="d-flex">
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
          <button class="btn btn-outline-success" type="submit">Search</button>
        </form>
      </div>
    </div>
  </nav>

Intégration

Nous ajoutons maintenant ce composant à notre composant principal

app.component.html
<app-header></app-header>
<router-outlet></router-outlet>

Test

À ce niveau là, l’application devrait être opérationnelle :

ng serve

Réglez les problèmes éventuels avant de poursuivre.

Création du composant PageTableMultComponent

ng generate component pageTableMult

La classe du composant ainsi crée donne :

/page-table-mult.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-page-table-mult',
templateUrl: './page-table-mult.component.html',
styleUrls: ['./page-table-mult.component.css']
})
export class PageTableMultComponent {

}

Configuration des routes

Le fichier app-routing-module.ts a été lors de la création de l’application (paramètre --routing).

Nous allons déclarer notre composant PageTableMult comme cible d’une route, que nous nommons 'table-multiplication'.

/src/app/app-routing-module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PageTableMultComponent } from './page-table-mult/page-table-mult.component';

const routes: Routes = [
  {path: 'table-multiplication', component: PageTableMultComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Nous pouvons maintenant faire référence à cette route dans le header.

extrait /src/app/compoment/header/header.component.html
[...]

<li class="nav-item">
   <a class="nav-link active" aria-current="page" href="#">Home</a>
</li>

<li class="nav-item">
   <a class="nav-link" ariaCurrentWhenActive="page"
      routerLink="/table-multiplication"
      routerLinkActive="active">
    Table Multiplication
   </a>
</li>

[...]

Test

À ce niveau là, le lien Table Multiplication dans la barre de menu de l’application devrait être opérationnel.

Réglez les problèmes éventuels avant de poursuivre.

Travaux pratiques

  1. Ajouter une partie footer au template de votre application. On attend de vous que vous ajoutiez un nouveau composant dédié à cet usage qui respecte la structure ci-dessous :

Diagram

Réglez les problèmes éventuels avant de poursuivre.

Conception du composant TableMultiplication

Le composant 'page' que nous venons de créer va exploiter un composant métier que nous appellerons TableMultiplication.

Ce composant aura la responsabilité de présenter une table de multiplication. Créons-le.

ng g component component/TableMultiplication

La vue du composant

Voici une première version de la vue de ce composant.

src/app/component/table-multiplication/table-multiplication.component.html
<div class="box center-div">
    <ul class="align-left">
        <li>Table de : {{n}}</li> (1)
        <li> <pre>---------</pre> </li>
        <li *ngFor="let item of [].constructor(10); let i = index"> (2)
          <span class="nmulti">{{n}}</span>
          <span>&nbsp;&nbsp;x </span>
          <span>{{i+1}}</span>
          <span> = </span>
          <span>{{n*(i+1)}}</span>
        </li>
    </ul>
</div>
1 La variable n (entre double accolades) est une des propriétés définies dans la classe du composant. C’est Angular qui permet de lier des variables de vue avec des propriétés de la classe TypeScript liée au composant. Un changement de valeur d’une telle propriété entraine automatiquement une mise à jour de la vue du composant.
2 ngFor est une expression de boucle d’Angular. item et i sont des variables de boucle. ngFor est une des directives structurelles d’Angular avec ngIf, ngSwitch : https://angular.io/guide/structural-directives

Le code du composant

Dans l’état actuel, le composant ne compile pas car la propriété n n’est pas déclarée dans la classe du composant. C’est ce que nous allons faire.

table-multiplication.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-table-multiplication',
  templateUrl: './table-multiplication.component.html',
  styleUrls: ['./table-multiplication.component.css']
})
export class TableMultiplicationComponent {

   n: number = 2 (1)

}
1 Une déclaration et initialisation d’une propriété, nommée n de type number, dans la plus simple expression.

Le composant en action

Nous allons faire en sorte que le composant de type page PageTableMult intègre dans sa vue le nouveau componsant dont le selecteur est app-table-multiplication.

Nous augmentons ainsi la hiérarchie des composants de notre application.

Diagram

Cette intégration se réalise dans la vue du composant page.

/src/app/page-table-mult/page-table-mult.component.html
<p>page-table-mult works!</p>
<app-table-multiplication></app-table-multiplication>

Testons le résultat :

vue du composant
Figure 1. route : /table-multiplication

Paramétrer le composant TableMultiplication

Dans son état actuel, le composant affichera toujours la table de multiplication par 2. Nous allons le paramétrer afin de pouvoir lui faire afficher une table de multiplication à la demande.

table-multiplication.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-table-multiplication',
  templateUrl: './table-multiplication.component.html',
  styleUrls: ['./table-multiplication.component.css']
})
export class TableMultiplicationComponent {

  @Input() n: number = 2 (1)

}
1 La directive @Input(), lorsqu’elle est placée devant le nom d’une propriété, permet de paramétrer le composant.

Tentons de passer une autre valeur que 2 à la propriété n de notre composant.

/src/app/page-table-mult/page-table-mult.component.html
<p>page-table-mult works!</p>
<app-table-multiplication [n]="3"></app-table-multiplication>

Vérifions ce travail.

Table Mult par 3

Explication : Dans la balise ouvrante du composant nous passons la valeur 3 que l’on souhaite attribuer à la propriété n du composant (décorée par @Input, pour que ça marche).

On remarquera la syntaxe qui, côté parent, utilise le crochet pour désigner la propriété à valoriser (n) du composant :

<app-table-multiplication [n]="3"></app-table-multiplication>

Travaux pratiques

  1. Ajouter la possibilité de permettre à l’utilisateur de saisir une valeur de n. Pour cela, prévoir un élément html input dans la vue du composant page-table-mult. Vous trouverez sur le net de nombreux exemples pour lier un <input> à une propriété d’un composant Angular.

  1. Ajouter une nouvelle page (et nouvelle route et nouveau lien dans la barre de menu) qui présente les tables de multiplication, de 1 à 10. Pour y arriver, vous mettrez en application ce qui a été vu précédemment.

Voici la nouvelle version de l’arbre hiérarchique de composants à implémenter :

Diagram
  1. Ajouter la possibilité de permettre à l’utilisateur de saisir le nombre de tables qu’il souhaite voir dans la table des tables de multiplication (ne pas le limiter à 10).