Rappel du besoin :
J’ai un objet application qui a 2 FK : une vers produit, une vers fonction.
Mon produit a également une référence vers fontion.
Lorsque je sélectionne un produit depuis une fiche d’application, je souhaite que la liste des produit affiché soit filtré par défaut avec la même fonction que sur mon application.
Dans le ticket suivant: Ajouter un filtre par défaut modifiable, vous évoquez notamment la mise en place d’un paramètre de session. Problème : le hook initRefSelect est exécuté 2 fois et il n’existe pas de critères permettant de “filtrer” ces exécutions afin de ne pas exécuter le code, lors d’un des 2 passages. En tout cas, pas de manière absolu.
Scénarii testés
Sur ma fiche d’édition de mon application, je clique sur l’attribut Produit. Cela m’ouvre une popup:
-> 1er appel initRefSelect appelé sans l’objet parent
-> 2e appel initRefSelect appelé avec l’objet parent : application
Sur ma fiche d’édition de mon application, je clique sur l’attribut Produit. Je sélectionne un produit. Je souhaite le changer. Je clique de nouveau sur l’attribut Produit. La popup s’ouvre de nouveau
-> 1er appel initRefSelect appelé avec l’objet parent : application
-> 2e appel initRefSelect appelé avec l’objet parent : application
Avez-vous une solution afin de ne pas exécuter le code du initRefSelect deux fois ?
Le 1er appel est fait par la UI pour récupérer les méta-data de l’objet en context REFSELECT, le parent n’a pas d’utilité à ce stade.
Le 2eme est le “search” à proprement parler pour lister les objets liés avec le parent demandé.
On va regarder si on peut s’affranchir du 1er appel, mais il se peut que la UI en ait besoin pour vérifier des choses avant de lancer la recherche, auquel cas il faudra aussi lui envoyer le parent.
Pourquoi ne pas juste tester que le parent est non nul et = Application dans votre code ? peu importe de faire le travail 2 fois si c’est simple/rapide (setFilter…). Un hook n’est jamais sensé faire des taches longues.
Le problème c’est que l’on souhaite positionner un filtre par défaut à l’ouverture mais qui soit modifiable par l’utilisateur.
On ne souhaitait mettre le filtre qu’au moment de l’ouverture de la popup. Dans la fiche " Ajouter un filtre par défaut modifiable, vous parlez de paramètre de session.
Je comptais donc mettre un paramètre dans le initUpdate de mon objet application et le supprimer dans le hook initRefSelect de mon produit. Le problème c’est que si on passe deux fois dans le hook, le deuxième passage dans le initRefSelect supprimera le filtre mis dans le premier appel.
Existe-t-il une façon “formelle” de différencier les deux appels ?
Après vérification, il est bien nécessaire de faire 2 appels :
1 pour mettre l’objet dans ce context et savoir si on peut créer des références, voir certains champs… avant affichage de la liste
et 1 second pour faire le search de la liste en fonction des filtres (linked ref), parent…
Il n’est pas utile de supprimer votre paramètre qui sera actualisé à chaque initUpdate.
Il faut plutôt le supprimer dans vos autres contextes de navigation ou le filtre n’est pas utile (initUpdate des autres objets qui ont cette référence, mais je vois pourquoi si le parent est déterminé).
et dans le initRefSelect un code unique :
if (parent!=null && parent.getName().equals("MyApplication")) {
String filter = getGrant().getParameter("MYFILTER");
if (filter!=null) getField(...).setFilter(filter);
}
j’ai le même problème dans la cadre du hook initAssociate qui est appelé deux fois.
Comment puis-je déterminer dans ce hook si je suis dans le premier appel ou le deuxième?
Dans les deux cas, parent et this.getParentObject() sont non nuls, les instances sont les mêmes…
Bruno
Je vais regarder si on peut s’affranchir de 2 appels, mais il se peut que la UI, comme dans le cas du initRefSelect, ait besoin de meta-data pour préparer l’objet avant de faire le search.
Sinon on peut toujours s’en sortir avec un test java du genre :
private boolean first = true;
public void initAssociate(ObjectDB parent) {
if (first) {
//...
}
first = !first;
}
La logique du flag “first” est en effet simple à mettre en place mais ce qui conviendrait ce serait une logique basée sur un flag “last”…
En suivant cette piste, je me demandais si il ne serait pas possible de distinguer le dernier des appels initiés par le moteur des précédents quel que soit leur nombre (actuellement 2 appels dans le context testé) éventuellement avec une information sur le contexte d’appel ou tout autre chose…
Il suffit de faire if (!first) pour se caler sur le appels pairs…
Sur le fond, je suis d’accord il faut qu’on arrive à trouver une astuce pour n’appeler ce hook qu’une seule fois mais c’est une question “d’oeuf et de poule” pour la UI pas simple à résoudre.
Je le note dans notre backlog V5, car je doute qu’on change ce comportement en V4, c’est trop risqué.
L’évolution a été faite en V5 pour n’appeler qu’une fois ces 2 hooks lors de l’affichage du popup :
La UI a besoin de charger les meta-data dans le contexte REFSELECT ou ASSOCIATE pour préparer la UI/droits…, puis d’appeler le service search dans ce même contexte pour lister les références.
C’est le back-end qui détecte qu’on est toujours dans le même contexte pour ne pas ré-appliquer le hook sur l’objet.
Attention, le hook initRefSelect peut aussi être appelé en cas de champ FK avec completion depuis le formulaire.
Ca ne sera pas backporté car nécessite de bien revoir ces hooks sensibles lors d’un upgrade majeur.
Il faut donc noter quelque part de vérifier votre règle de gestion quand vous passerez en V5, et retirer la bidouille algorithmique type if (odd(++i))…