Introduction
Dans cet article, nous allons explorer la mise en place d’une vue contenant un tableau interactif composé de plusieurs colonnes et lignes. Ce tableau servira à illustrer une bonne pratique en matière d’interface utilisateur (UI) et d’expérience utilisateur (UX), en mettant l’accent sur l’intuitivité et la simplicité d’utilisation. L’objectif est de garantir une navigation fluide et un rendu visuel agréable, permettant à l’utilisateur d’interagir facilement avec les données présentées.
En plus du tableau, des boutons d’action seront intégrés pour effectuer des mappings entre les données du tableau et une base de données. Bien que les appels API pour ces interactions soient simulés dans ce projet, l’accent est mis sur l’aspect UI/UX, avec un design épuré, des interactions fluides et une expérience utilisateur optimale.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
- Node.js version 18 ou supérieure pour la compatibilité avec Angular 18.
- Yarn comme gestionnaire de paquets.
- Connaissances de base en Angular.
- Une bonne compréhension de Bootstrap pour concevoir une interface utilisateur responsive.
Use Case
Imaginons un cas d’utilisation où vous devez afficher un grand nombre de données issues d’un fichier Excel dans un tableau Bootstrap. Chaque ligne représente un produit et chaque colonne des attributs spécifiques de ces produits (comme l’ID, le nom, la description, etc.).
Le tableau doit permettre à l’utilisateur de visualiser les données facilement et d’effectuer un mapping entre certaines colonnes et les champs de la base de données via un bouton d’action associé à chaque ligne. Ce mapping sera effectué à l’aide de menus déroulants et d’actions simulées, permettant une expérience utilisateur cohérente et intuitive. Le but ici n’est pas de mettre en place une logique serveur complète, mais plutôt de montrer comment concevoir une interface fluide qui permet à l’utilisateur d’interagir efficacement avec un tableau de données.
Grâce à cette mise en place, nous chercherons à optimiser le confort d’utilisation du tableau et la clarté des actions disponibles pour l’utilisateur.
Installation du Projet Angular
Installer Angular CLI
Si Angular CLI n’est pas déjà installé sur votre machine, vous pouvez l’installer en utilisant Yarn avec la commande suivante :
yarn global add @angular/cli@18
Créer un Nouveau Projet Angular
Une fois Angular CLI installé, créez un nouveau projet en exécutant la commande suivante dans votre terminal :
ng new angular-table-example --style=scss --routing --ssr
angular-table-example
est le nom de notre projet. Vous pouvez choisir un autre nom.
Lancer le Serveur de Développement
Entrez dans le répertoire de votre projet et lancez le serveur de développement avec les commandes suivantes :
cd angular-table-example
ng serve
Votre projet Angular est maintenant disponible à l’adresse http://localhost:4200. Vous pouvez accéder à cette URL dans votre navigateur pour voir la page d’accueil par défaut d’Angular.
Installation des Modules
Installer Bootstrap
Nous allons utiliser Bootstrap pour styliser notre tableau et nos boutons. Installez Bootstrap avec la commande suivante :
yarn add bootstrap
Ensuite, ouvrez le fichier angular.json
et ajoutez le chemin vers les fichiers CSS de Bootstrap dans la section projects > angular-table-example > architect > styles
:
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
]
Cela permettra de charger les styles de Bootstrap dans votre projet Angular.
Configurer un Spinner
Nous allons utiliser un package d’icônes comme Font Awesome pour styliser facilement les boutons et loaders. Pour l’installer :
yarn add @fortawesome/fontawesome-free
Ajoutez également le chemin vers le fichier CSS de Font Awesome dans angular.json
:
"styles": [
"src/styles.css",
"node_modules/@fortawesome/fontawesome-free/css/all.min.css"
]
Installer ngx-toastr
Nous allons pouvez utiliser une bibliothèque comme ngx-toastr pour afficher des messages de toast plus élégants et non intrusifs. Exécutez la commande suivante pour installer la bibliothèque :
yarn add ngx-toastr
yarn add @angular/animations
Ajoutez le chemin vers le fichier CSS de ngx-toastr dans angular.json
:
"styles": [
"src/styles.css",
"node_modules/ngx-toastr/toastr.css"
]
Ajoutez les modules nécessaires dans votre application. Ouvrez votre fichier app.config.ts
et configurez-le comme suit au niveau des providers :
providers: [
//...,
provideToastr({
timeOut: 2000,
positionClass: 'toast-top-right',
preventDuplicates: true,
}),
provideAnimations()
]
Création du Composant
Maintenant que notre projet est configuré, nous allons créer un composant Angular pour afficher et gérer les données dans un tableau.
Créez un nouveau composant en utilisant la commande suivante dans le terminal :
ng generate component DataManagement
Cela créera automatiquement les fichiers nécessaires : un fichier TypeScript (data-management.component.ts
), un fichier HTML (data-management.component.html
), et un fichier CSS/SCSS (data-management.component.scss
).
Ajouter la Logique
Dans le fichier data-management.component.ts
, ajoutez la logique suivante pour simuler un appel à une API et gérer les actions utilisateur :
import { CommonModule } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { ToastrService } from 'ngx-toastr'; @Component({ selector: 'app-data-management', standalone: true, imports: [CommonModule], templateUrl: './data-management.component.html', styleUrl: './data-management.component.scss' }) export class DataManagementComponent implements OnInit { dataPreview: any[] = []; columns: any[] = []; isDeleting: boolean = false; isTesting: boolean = false; isImporting: boolean = false; mappingList: { label: string; value: string }[] = []; constructor(private toastr: ToastrService) { } ngOnInit() { this.loadData(); this.initializeMappingList(); } loadData() { setTimeout(() => { this.dataPreview = this.generateData(30); this.columns = this.getColumns(); }, 2000); } initializeMappingList() { this.mappingList = [ { label: 'Field A', value: 'FieldA' }, { label: 'Field B', value: 'FieldB' }, { label: 'Field C', value: 'FieldC' }, { label: 'Field D', value: 'FieldD' } ]; } generateData(count: number) { const data = []; for (let i = 0; i < count; i++) { data.push({ id: i + 1, label: `Label-${i + 1}`, company: `Company-${i + 1}`, product: `Product-${i + 1}`, description: `Description for Product-${i + 1}`, status: i % 2 === 0 ? 'Active' : 'Inactive', price: (Math.random() * 100).toFixed(2) }); } return data; } getColumns() { return [ { id: 'label', label: 'label' }, { id: 'company', label: 'Company Name' }, { id: 'product', label: 'Product Name' }, { id: 'description', label: 'Extremely long Product Description' }, { id: 'status', label: 'Status' }, { id: 'price', label: 'Price ($)' } ]; } deleteData() { this.isDeleting = true; setTimeout(() => { this.isDeleting = false; this.toastr.success('Action successfully deleted.'); }, 1500); } importTest() { this.isTesting = true; setTimeout(() => { this.isTesting = false; this.toastr.success('Test successfully completed.'); }, 1500); } importData() { this.isImporting = true; setTimeout(() => { this.isImporting = false; this.toastr.success('Data successfully imported.'); }, 1500); } }
Dans cette logique, nous avons :
dataPreview
: Contiendra les données fictives.columns
: Définira les colonnes du tableau.- Trois états de chargement (
isDeleting
,is
Testing,isImporting
) : Pour gérer les spinners lors des actions utilisateur.
Création du Tableau
Dans le fichier data-management.component.html
, affichez les données sous forme de tableau avec un header fixe et ajoutez les boutons pour la suppression et la mise à jour :
<div class="container pt-5"> <div class="table-actions"> <div class="action-buttons"> <button class="btn btn-secondary"> <i class="fas fa-chevron-left"></i> Back </button> <button class="btn btn-danger" (click)="deleteData()" [disabled]="isDeleting"> <i class="fas fa-ban" *ngIf="!isDeleting"></i> <div class="spinner-grow text-light sizespinner" *ngIf="isDeleting" role="status"> <span class="sr-only">Loading...</span> </div> Delete </button> </div> <div class="action-buttons"> <button class="btn btn-warning" (click)="importTest()" [disabled]="isTesting"> <i class="fas fa-vial" *ngIf="!isTesting"></i> <div class="spinner-grow text-light sizespinner" *ngIf="isTesting" role="status"> <span class="sr-only">Loading...</span> </div> Test </button> <button class="btn btn-success" (click)="importData()" [disabled]="isImporting"> <i class="fas fa-file-import" *ngIf="!isImporting"></i> <div class="spinner-grow text-light sizespinner" *ngIf="isImporting" role="status"> <span class="sr-only">Loading...</span> </div> Import </button> </div> </div> <div class="table-container"> <table class="table table-bordered"> <thead> <tr> <th class="number">#</th> <th *ngFor="let column of columns"> {{ column.label }} <select class="form-control"> <option value="">-- No selection --</option> <option *ngFor="let product of mappingList" [value]="product.label"> {{ product.label }} </option> </select> </th> </tr> </thead> <tbody> <tr *ngFor="let row of dataPreview"> <td class="number">{{ row.id }}</td> <td *ngFor="let column of columns">{{ row[column.id] }}</td> </tr> </tbody> </table> </div> </div>
Les boutons déclenchent les actions et les spinners sont affichés lorsque des processus sont en cours (suppression, simulation, mise à jour).
Stylisation du Tableau avec un Header Fixe
Ajoutez le style suivant dans le fichier data-management.component.scss
pour fixer le header ainsi que la première colonne du tableau et styliser les spinners :
/* Section for buttons */ .table-actions { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } /* Container for buttons on the right */ .action-buttons { display: flex; gap: 10px; } /* Buttons */ button.btn { padding: 8px 16px; font-size: 14px; } /* Fix equal width for all table columns */ table { table-layout: fixed; width: 100%; border-collapse: separate; border-spacing: 0; } th, td { width: 150px; text-align: center; padding: 8px; border: 1px solid lightgrey; } select.form-control { width: 100%; } /* Styles for the header */ thead th { background-color: #f8f9fa; font-weight: bold; position: sticky; top: 0; /* To keep the header above the content */ box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4); /* A separation effect */ z-index: 10; } /* Fix the first column */ td.number { position: sticky; left: 0; background-color: #f8f9fa; /* White background for the fixed column */ z-index: 5; } /* Handle longer headers */ thead th select { font-size: 14px; width: 100%; min-height: 36px; } .number { width: 50px; } .table-container { overflow-x: auto; max-height: 80vh; /* Limit table height to allow vertical scrolling */ } /* Apply a fixed style for the header */ .table-container thead th { position: sticky; top: 0; z-index: 10; margin-top: -5px; } .sizespinner { size: 1rem; } .spinner-grow { display: inline-block; width: 1rem !important; height: 1rem !important; }
Intégration dans le Composant App
Une fois que vous avez suivi toutes les étapes ci-dessus et que votre serveur de développement est en cours d’exécution, vous pouvez ajouter votre composant dans le fichier app.component.ts
et app.component.html
pour rendre votre nouveau composant visible :
import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { DataManagementComponent } from './data-management/data-management.component'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, DataManagementComponent], templateUrl: './app.component.html', styleUrl: './app.component.scss' }) export class AppComponent { title = 'angular-table-example'; }
<app-data-management></app-data-management>
Tests
Ouvrez votre navigateur et naviguez à l’adresse http://localhost:4200.
Conclusion
En conclusion, la mise en place d’un tableau interactif dans Angular, enrichi de fonctionnalités UI/UX telles que les boutons d’action, les spinners et la gestion des mappings, illustre l’importance d’une interface utilisateur fluide et intuitive. L’intégration de Bootstrap, Font Awesome, et ngx-toastr renforce l’esthétique et la réactivité de l’application, tout en simplifiant l’expérience utilisateur. En suivant ces bonnes pratiques, vous pouvez créer des interfaces efficaces et ergonomiques, capables de gérer de grands ensembles de données tout en offrant une expérience utilisateur optimale.
Architecte logiciel, Développeur d'application diplomé d'ETNA, la filière d'alternance d'Epitech, j'ai acquis une expertise solide dans le développement d'applications, travaillant sur des projets complexes et techniquement diversifiés. Mon expérience englobe l'utilisation de divers frameworks et langages, notamment Symfony, Api Platform, Drupal, Zend, React Native, Angular, Vue.js, Shell, Pro*C...