Aller au contenu principal

Composant Tree

Tree sert à représenter des catégories de produits, des organigrammes, des dossiers, des zones géographiques et toute autre donnée hiérarchique. Une petite arborescence stable peut être maintenue directement dans la page. Si les données appartiennent à un système métier, chargez les racines et les enfants depuis une API.

1. Choisir le mode de configuration​

BesoinConfiguration recommandée
Petite liste stable gérée par les auteursTree Nodes statiques
Hiérarchie gérée par un système métierTree Data Source
Création, modification, suppression ou commandes contextuellesSource dynamique + Node Actions
Réorganisation ou déplacement de branchesSource dynamique + onDrop

1.1 Tree : catégories de produits statiques​

L’exemple statique écrit d’abord [[treeNode.name]] dans selectedCategory avec Set Page Context, puis appelle reloadTable sur le ProTable. Dans Query Context, le paramètre category lit cette valeur.

1.2 Tree02 : chargement dynamique et édition​

Tree02 charge les racines à l’ouverture, puis les enfants directs avec parentId lorsqu’un dossier est développé. Il illustre aussi la recherche serveur, les détails, l’ajout, la modification, la suppression et l’enregistrement d’un glisser-déposer. Validez ces fonctions dans cet ordre afin d’isoler plus facilement une erreur.

2. Ajouter un Tree​

  1. Ouvrez la page dans Page Designer et sélectionnez Screen.
  2. Ajoutez Tree dans la zone enfant Navigation Tree.
  3. Pour des données statiques, ajoutez des Tree Nodes.
  4. Pour une API, ajoutez Tree Data Source dans Data Source.
  5. Placez le ProTable, le Form ou un autre contenu dans Panels.

Navigation Tree forme la zone de navigation à gauche. Panels et Grids forment automatiquement la zone de contenu.

3. Configurer le Tree​

PropriétéRôle
TitleTitre facultatif au-dessus de l’arbre
WidthLargeur sur ordinateur ; la zone passe sur une ligne complète sur petit écran
Show SearchAffiche la recherche
CheckableAffiche les cases à cocher
Default Expand AllDéveloppe les nœuds déjà chargés au premier affichage
Node DraggableAutorise le glisser-déposer et déclenche onDrop

4. Nœuds statiques​

Ajoutez des TreeNode dans Tree Nodes, puis renseignez Title, Value, Disabled, Selectable, Checkable, Is Leaf, Icon et Extra Info. Value doit rester unique et stable dans tout l’arbre, car les interactions l’utilisent pour identifier le nœud.

5. Source de données dynamique​

Ajoutez TreeDataSource dans Data Source et commencez par la requête des racines :

RéglageExemple Tree02
Root Data URL/spark/api/sample/navigation/tree/nodes
Request MethodGET
Response List Pathdata.nodes
Title Fieldlabel
Value Fieldid
Children Fieldchildren
Leaf Fieldleaf
Extra Fieldcount

5.1 Vérifier avec Test​

Cliquez sur Test. Le test, le canevas et la page exécutée partagent la même construction de requête et la même analyse de réponse. Le résultat permet donc de distinguer un problème d’URL, de données backend, de Response List Path ou de correspondance des champs.

Spark ajoute automatiquement :

X-Spark-Page-Environment: DEV
X-Spark-Page-Render-Mode: DESIGN_PREVIEW

Ne les ajoutez pas manuellement dans Data Source. Consultez Contexte de requête de page et débogage backend pour le protocole complet.

Le backend doit analyser les en-têtes avec le contrat partagé, puis comparer les valeurs d’énumération :

SparkPageRequestContext context = SparkPageRequestHeaders.resolve(
environment, renderMode);
boolean developmentPreview = context != null
&& context.getEnvironment() == SparkPageEnvironment.DEV
&& context.getRenderMode() == SparkPageRenderMode.DESIGN_PREVIEW;

Les données de prévisualisation doivent être déterministes et ne jamais contenir de secrets, de données personnelles ou de données de production sensibles.

5.2 Chargement complet ou différé​

Une petite arborescence peut être renvoyée entièrement dans children. Pour un grand volume, configurez Child Nodes URL et Parent Parameter. Lors du développement d’un nœud non terminal, Tree transmet sa Value, par exemple dans parentId. Un dossier doit renvoyer leaf: false, même si children est encore vide.

6. Recherche​

La recherche locale convient aux données statiques ou déjà chargées. Avec le chargement différé, configurez Search URL et son paramètre. Le serveur doit renvoyer les ancêtres des nœuds trouvés afin de préserver leur contexte.

7. Nœud courant et contexte d’événement​

ÉvénementDonnées usuelles
onClicktreeNode, selectedTreeNode
onChecktreeCheck.checkedKeys, treeCheck.checkedNodes
onExpandtreeExpand.expandedKeys, treeExpand.node
onLoadtreeLoad.node, treeLoad.children
onDroptreeDrop.dragNode, treeDrop.dropNode, treeDrop.position

Les chemins les plus utiles sont treeNode.value, treeNode.title, treeNode.isLeaf et treeNode.data.category. Une Node Action met le nœud courant à jour sans déclencher simultanément onClick.

8. Configurer les actions de nœud​

Ajoutez un TreeNodeAction sous Node Actions. Définissez le titre, l’icône au moyen du sélecteur partagé, le déclencheur, le ton, la condition d’affichage et la condition de désactivation. Le bouton More et le menu contextuel utilisent la même liste ; sur écran tactile, utilisez More plutôt qu’un appui long.

PUT /spark/api/sample/navigation/tree/nodes/[[treeNode.value]]
POST /spark/api/sample/navigation/tree/nodes
DELETE /spark/api/sample/navigation/tree/nodes/[[treeNode.value]]

Configurez l’interaction sur la Tree Node Action et appelez reloadTree uniquement après une requête réussie. Masquer une commande ne remplace jamais le contrôle d’autorisation du backend.

9. Glisser-déposer et persistance​

Avec Node Draggable, Tree déplace d’abord le nœud à l’écran, puis déclenche onDrop. treeDrop.position vaut BEFORE, INSIDE ou AFTER. Pour enregistrer le résultat, ajoutez Send Request :

POST /spark/api/sample/navigation/tree/reorder

Envoyez dragId = [[treeDrop.dragNode.key]], dropId = [[treeDrop.dropNode.key]] et position = [[treeDrop.position]]. En cas d’échec ou d’interruption, Tree restaure la structure précédente. Le serveur doit vérifier les nœuds, le parent, les cycles, les droits et les modifications concurrentes.

10. Actualiser le contenu après une sélection​

Dans le Tree statique, onClick écrit d’abord [[treeNode.name]] dans selectedCategory, puis appelle reloadTable. Dans Tree02, écrivez [[treeNode.value]] dans selectedNodeId et [[treeNode.data.category]] dans selectedCategory, puis rechargez le ProTable. Cet ordre est indispensable : sinon le tableau réutilise la sélection précédente.

11. Fonctions du composant​

FonctionEffet
reloadTreeRecharge les racines et conserve une sélection encore valide
expandAllDéveloppe tous les dossiers déjà chargés
collapseAllRéduit tous les dossiers

expandAll ne charge pas automatiquement toutes les branches absentes d’un grand arbre différé.

12. Exemple de backend Java​

Le contrat Tree02 cible Java 17 et Spring Boot 4. Le DTO de nœud expose au minimum id, label, parentId, leaf et children. Les requêtes d’écriture utilisent parentId, label, category ; la réorganisation utilise dragId, dropId, position.

UsageMéthode et chemin
Racines, enfants et rechercheGET /spark/api/sample/navigation/tree/nodes
Ajouter un enfantPOST /spark/api/sample/navigation/tree/nodes
Modifier un nœudPUT /spark/api/sample/navigation/tree/nodes/{nodeId}
Supprimer un nœudDELETE /spark/api/sample/navigation/tree/nodes/{nodeId}
Enregistrer un déplacementPOST /spark/api/sample/navigation/tree/reorder

Le service peut choisir des données de prévisualisation reproductibles ou le dépôt de l’environnement demandé :

Map<String, NodeRecord> source = isDevelopmentPreview(context)
? designPreviewNodes : nodes;
String keyword = StringUtils.trimToNull(query);
if (keyword != null) {
return children(source, null).stream()
.map(root -> filterTree(source, root, keyword))
.filter(Objects::nonNull)
.toList();
}
return children(source, StringUtils.trimToNull(parentId)).stream()
.map(node -> toDto(source, node))
.toList();

Le backend doit revalider les nœuds, les parents, les cycles et les droits pour chaque écriture. Les erreurs visibles utilisent LatticeRuntimeException(Message.code(...)) et les ressources i18n du serveur, jamais une chaîne assemblée dans le Service. La mise à jour du parent et de l’ordre des frères doit être atomique.

Le ProTable de droite peut ajouter nodeId à sa requête. Les catégories continuent d’utiliser category, tandis que le backend traduit les nœuds métier en filtres adaptés.

13. Validation et dépannage​

Validez successivement le chargement, la sélection, les commandes de nœud et la persistance du glisser-déposer. Commencez par Test, vérifiez l’ouverture des enfants et la recherche, puis sélectionnez plusieurs nœuds et confirmez que le tableau change avant de tester les écritures.

SymptômePremier contrôle
Échec de TestURL, méthode, connexion, authentification et CORS
HTTP 200 mais aucun nœudResponse List Path doit pointer vers un tableau
Nombre visible, titre absentTitle Field, Value Field et noms JSON réels
Dossier impossible à développerLeaf Field renvoie peut-être true par erreur
Même liste pour plusieurs nœudsOrdre du Page Context et chemins du Query Context
Ordre perdu après actualisationParamètres onDrop et persistance backend