Components
Interne
Les composants partagés sont définis dans le dossier shared/components
voir code
Editable Bloc
Ce composant sert à gérer l'édition de données en tant que bloc de la page de détail d'une ressource.
Après mise à jour avec succès du back-end, il faut mettre à jour le composant pour que les nouvelles valeurs par défaut du formulaire correspondent aux nouvelles valeurs sauvegardées. Si on omet cela, la fonction reset
du formulaire appelée lors du clic sur le bouton "Annuler" va réinitialiser le formulaire à sa valeur initiale lors du premier chargement de la page.
this.editableBloc.resetState(this.form.getRawValue()); // ici on utilise form.getRawValue qui est la valeur actuelle du formulaire qui a été envoyé au back-end
Simple
Paginated
Externe
Cdk-Tree
On se base sur le CDK d'Angular pour construire des arborescences dépliables.
Cas 1 : Tous les éléments sont préchargés
Exemple arborescence document manager
- Définition d'un type
TreeNode
contenant les informations des noeuds. - Définition d'une méthode indiquant si un noeud à des enfants (utilisé dans le template).
- Initialisation d'une source de données "dataSource" (passée au cdk-tree).
- Initialisation d'un
TreeControl
permettant au cdk de manipuler les noeuds. - Définition du template
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
<!-- template d'un noeud terminal "sans enfant" -->
<cdk-nested-tree-node
*cdkTreeNodeDef="let node"
class="tree-node"
[ngClass]="{
'active-node': isNodeActive(node),
'hover-node': node.hover
}"
(click)="activateNode(node)"
(mouseover)="node.hover = true"
(mouseout)="node.hover = false"
>
{{ node.name }}
</cdk-nested-tree-node>
<!-- template d'un noeud avec enfant dépliable/repliable -->
<!-- hasChild est la méthode indiquant si un noeud a des enfants -->
<cdk-nested-tree-node
*cdkTreeNodeDef="let node; when: hasChild"
class="tree-node"
[ngClass]="{
'hover-node': node.hover
}"
(mouseover)="node.hover = true"
(mouseout)="node.hover = false"
>
<button
[attr.aria-label]="'Toggle ' + node.name"
cdkTreeNodeToggle
class="btn p-0 text-start"
>
<fa-icon
[icon]="treeControl.isExpanded(node) ? icons.fold : icons.unfold"
></fa-icon>
{{ node.name }}
</button>
<div [class.d-none]="!treeControl.isExpanded(node)">
<!-- container des noeuds enfant (géré par le cdk tree) -->
<ng-container cdkTreeNodeOutlet></ng-container>
</div>
</cdk-nested-tree-node>
</cdk-tree>
Lors d'un rechargement dynamique d'élément de cette arborescence et notamment lors de la suppression de certain noeud, il faut s'assurer de passer au TreeControl
une fonction trackBy
en configuration qui permet de gérer l'identité d'un noeud. Si on l'omet : les éléments supprimés resteront affichés.
treeControl = new NestedTreeControl<DocumentTreeNode, string>(
(node) => node.children,
{
trackBy: trackByFn, // (node: TreeNode) => string
},
);
En revanche il ne faut pas passer de propriété trackBy
au composant cdk-tree
, un problème d'implémentation empêche la suppression des noeuds (see issue)
Cas 2 : On charge les enfants d'un noeud dynamiquement
Exemple arborescence structures
Afin de réfleter les ajouts de noeuds il est important d'utiliser un Observable
pour mettre à jour les enfants et s'assurer que le tree "voit" les mises à jour, ici on utilise un BehaviorSubject
.
export interface StructureTreeNode {
id: number;
intitule: string;
children: BehaviorSubject<StructureTreeNode[]>;
loading = false;
}
On écoute dynamiquement les actions de pliage/dépliage des noeuds qui sont executés par la directive CdkTreeNodeToggle
pour charger les enfants.
this.treeControl.expansionModel.changed.subscribe((change) => {
//change.added = expanding node / change.removed = collapsing node
if (change.added) {
// change.added is a list to handle case where multiple nodes are affected at the same time
change.added.forEach((node) => this.loadChildren(node));
}
}),
Il est déconseillé d'ajouter la configuration trackBy
au TreeControl dans ce cas car cela change la nature des évènements de changement, ils n'émettent plus des noeuds mais des id correspondant au retour de la méthode trackBy
, ce qui implique de recherche le noeud dans le dataSource pour mettre à jour les enfants.
treeControl = new NestedTreeControl<StructureTreeNode, number>(
(node) => node.children,
{
trackBy: (node) => node.id, //return a number
},
);
this.treeControl.expansionModel.changed.subscribe((change) => {
// change is automatically typed as SelectionChange<number>, the param node is now a number
change.added.forEach((node) => this.loadChildren(node));
}),
Stepper
On se base sur le CDK d'Angular pour construire des formulaires sur plusieurs étapes.
//TODO: complete docs