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 ».
https://fr.wikipedia.org/wiki/Table_de_multiplication
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
et une autre page présentant 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.
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.
<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>
Création du composant PageTableMultComponent
ng generate component pageTableMult
La classe du composant ainsi crée donne :
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'.
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.
[...]
<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>
[...]
Travaux pratiques
-
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 :
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.
<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> 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.
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.
Cette intégration se réalise dans la vue du composant page.
<p>page-table-mult works!</p>
<app-table-multiplication></app-table-multiplication>
Testons le résultat :
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.
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.
<p>page-table-mult works!</p>
<app-table-multiplication [n]="3"></app-table-multiplication>
Vérifions ce travail.
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
-
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 composantpage-table-mult
. Vous trouverez sur le net de nombreux exemples pour lier un<input>
à une propriété d’un composant Angular.
-
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 :
-
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).