Dans cet article tutoriel, nous allons voir comment créer un tableau de bord sur lequel l'utilisateur va pouvoir choisir les widgets qu'il souhaite afficher. On aura une collection de widgets qu'Angular chargera au besoin.
L'objectif est d'éditer un tableau de bord qui affichera les différents widgets que l'utilisateur aura choisis. Il pourra choisir dans une liste les widgets qu'il souhaite afficher. Un bouton "+" lui permettra de les ajouter.
Un service sera responsable de ramener la liste de widgets, qui seront simplement des components AngularAngular est un framework de développement JavaScript populaire basé sur TypeScript..
Le tableau de bord récupérera cette liste et affichera chaque widget. On pourra ajouter ou supprimer un type de widget sans affecter la gestion de l'ensemble
C'est parti pour le tuto Angular !
Commençons par créer le tableau de bord qui va afficher les widgets.
Son rôle est uniquement d'afficher la liste des widgets.
On la récupère dans l'initialisation du composant et elle sera maintenue à jour
par le service WidgetService
.
@Component({
selector: 'app-dashboard',
template: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
// La liste des définitions des widgets
// Plus d'info sur le type WidgetDefinition dans la suite de l'article :)
public $widgetList: Observable<WidgetDefinition<unknown>[]>;
constructor(
private widgetService: WidgetService
) {
}
ngOnInit(): void {
this.$widgetList = this.widgetService.getWidgets();
}
}
Le HTMLHTML (HyperText Markup Language) est un langage permettant de décrire le découpage d'une page web. est, lui aussi, assez simple.
<h1>dashboard works!</h1>
<div class="widget-container">
<!-- On parcourt la liste des widgets -->
<ng-container *ngFor="let widget of $widgetList | async">
<!-- C'est dans ce component que la magie opère -->
<app-widget
[ngClass]="widget.classCss"
[widget]="widget"
></app-widget>
</ng-container>
</div>
On va maintenant avoir besoin de définir nos widgets pour continuer !
Pour afficher les components, on va devoir définir du type de component à créer. On peut y ajouter quelques données pour que les widgets soient paramétrables et pourquoi pas une classe CSSFeuilles de style qui permettent de mettre en forme des pages web. pour pouvoir, par exemple, afficher plusieurs tailles de widget ;)
export class WidgetDefinition<T> {
classCss: WidgetClass;
widgetComponent: Type<T>;
widgetData: any;
}
export enum WidgetClass {
Size2x2 = 'size2x2',
Size4x4 = 'size4x4'
}
On utilise le type Type
importé avec import {Type} from '@angular/core';
et qui est utilisé par Angular pour représenter un component :
Par exemple Type<WidgetHorlogeComponent>
Étant donné qu'on ne saura pas avec quel component on va travailler, on utilisera le mot clé unknown
de TypeScript, qui correspond a un type any
mais ne permet pas d'effectuer des opérations sur cette variable.
Une dernière chose est que nos widgets doivent avoir une structure commune pour qu'on puisse les paramétrer, sinon où va-t-on injecter les widgetData ?
On va donc ajouter une dernière interface que les widgets devront implémenter.
export interface WidgetInterface {
data: string;
}
Ce component sera en quelque sorte un container pour les implémentations de widgets qui seront sélectionnables dans le dashboard.
Encore une fois pour le HTML, restons simple.
Nous allons simplement afficher un titre suivi du widget qui sera injecté dans le template.
<p>Widget</p>
<ng-template appWidgetHost></ng-template>
Pour pouvoir injecter le component on va devoir définir une nouvelle directive pour accéder à la vue du template, ce qui nous permettra de remplacer le template par notre widget.
@Directive({
selector: '[appWidgetHost]'
})
export class WidgetHostDirective {
// Ce viewContainerRef nous permettra de remplacer le contenu du template
constructor(public viewContainerRef: ViewContainerRef) { }
}
On a tout mis en place, il ne nous reste plus qu'à dire à Angular de créer le component passé en paramètre dans notre template !
Les anciennes version d'Angular ( < 13 ) devront utiliser le ComponentFactoryResolver
fourni dans angular/core. Comme son nom l'indique, ce service permet d'accéder directement au factory utilisé qu'Angular créé et donc d'instancier nous-même les components.
À partir d'Angular 13, il est permis de créer un component passant simplement son Type
au ViewContainer
.
@Input() widget: WidgetDefinition<unknown>;
// {static: true} permet d'accèder à la vue dans le ngInit
// Si c'est obligatoire pour l'ajout dynamique de component, c'est en revanche déconseillé dans la
// majorité des autres usages
@ViewChild(WidgetHostDirective, {static: true}) widgetHost: WidgetHostDirective;
constructor(
// Pour Angular < 13
// private componentFactoryResolver: ComponentFactoryResolver
) {
}
public ngOnInit(): void {
// Dans les version d'Angular < 13 on doit récupère la factory pour le type de widget
// const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.widget.widgetComponent);
// L'emplacement où l'on va injecter le widget
const viewContainerRef = this.widgetHost.viewContainerRef;
// On vérifie qu'il n'y a rien d'affiché
viewContainerRef.clear();
// Il ne reste plus qu'à créer le widget et injecter ces données
// Pour les anciennes versions on injectera la componentFactory à la place du Type du widget
const componentRef = viewContainerRef.createComponent<any>(this.widget.widgetComponent);
componentRef.instance.data = this.widget.widgetData;
}
On peut définir deux ou trois widgets. Ce sont des components qui vont implémenter l'interface WidgetInterface
On a défini WidgetHorlogeComponent
et de la même façon WidgetMeteoComponent
@Component({
selector: 'app-widget-horloge',
template: `<p>Heure : {{data}}</p>`,
styleUrls: ['./widget-horloge.component.css']
})
export class WidgetHorlogeComponent implements WidgetInterface {
data: any;
}
@Component({
selector: 'app-widget-meteo',
template: `<p>Météo : {{data}}</p>`,
styleUrls: ['./widget-meteo.component.css']
})
export class WidgetMeteoComponent implements WidgetInterface {
data: any;
}
Il ne reste plus qu'à créer le service qui pourvoira notre application en widget et le tour sera joué !
Il va simplement maintenir un observable à jour qui contiendra la liste des widgets.
// Quelques widgets par defaut
public widgetList: WidgetDefinition<unknown>[] = [
{
classCss: WidgetClass.Size2x2,
widgetComponent: WidgetMeteoComponent,
widgetData: 'Nuageux cette après-midi',
},
{
classCss: WidgetClass.Size4x4,
widgetComponent: WidgetHorlogeComponent,
widgetData: '04:20',
}
];
$widgetSubject = new ReplaySubject();
constructor() {
// On initialise simplement la liste des widgets
this.$widgetSubject.next(this.widgetList);
}
public getWidgets(): Observable<any> {
return this.$widgetSubject;
}
Si vous avez suivi toutes ces étapes, bravo ! Le dashboard est désormais opérationnel et charge correctement les widgets par défaut.
Le plus dur est fait et il ne reste que quelques adaptations pour que les utilisateurs puissent ajouter et supprimer des widgets à leur guise, un peu de CSS pour faire joli, mais pour ça, on vous laisse faire ! ;)
Besoin d'expertise pour votre projet Angular ? Contactez-nous pour qu'on en discute !
Présentation et comparatif des deux types de formulaires Angular : reactives forms et driven forms.
Afin de compléter son panel d’offre SOA, l’éditeur Français Talend a développé une offre MDM se basant en repartant de son désormais fameux studio ETL. Cette offre permet de construire un entrepôt de données via la modélisation d’un Data Model puis de gér
Tuto Hibernate - Dans cet article, nous voyons comment ramener plusieurs champs mais pas tous.