Actions en cascade sans attente précédente
Étiquetté : best practices, Fonctions, power apps, powerapps
-
Actions en cascade sans attente précédente
Posté par JLF sur 2 mai 2022 à 16h00Bonjour à la communauté
j’ai un processus d’enregistrement de saisies du type ticketting dans 3 listes différentes.
mon process se décompose comme suit:
1- rafraichissement de la liste principale (TICKET)
2- création numéro ticket en récupérant le nombre d’items existants
3- récupération des saisies dans 3 collections (avec traitements pour uniformiser mes données)
4- enregistrement dans les listes TICKET, TECHNIQUE et HABILITATIONchaque étape est dans un OnSelect de boutons (que je trouvais plus pratiques que d’avoir tout dans la minuscule fenêtre d’édition)
mon souci est que le rafraichissement de la liste principale met un peu de temps et mon numéro créé à la volée du coup reste à vide alors que mes autres actions suivantes elles continuent et évidemment ne peuvent se réaliser vu que le numéro de ticket est obligatoire
en fait comment pour que chaque process (là OnSelect) attende que le précédent soit terminé ?
Merci bien
PostID=QwgjeaKmdvRNPuH
JLF a répondu Il y a 10 mois, 2 semaines 1 Membre · 12 Réponses -
12 Réponses
-
je précise: je suis une bille en anglais 😥
et même avec la traduction auto pas évident d’y comprendre quelque choseCommentID=Ys3zZkT66KilaWy, PostID=QwgjeaKmdvRNPuH
-
Bonjour @JLF,
Malheureusement, c’est le fonctionnement de la fonction Select(), l’action est enregistrée dans une file d’attente pour une exécution non immédiate et dont il n’est pas possible de récupérer le retour d’exécution.
Tu peux éventuellement déplacer tes appels aux boutons dans chacun des boutons qui exécute le code précédent.
A la fin du OnSelect() sur le bouton action_Refresh_1, Select(action_RECORD_num_1)
A la fin du OnSelect() sur le bouton action_RECORD_num_1, Select(action_colTICKET_get_1)
Ainsi de suite…Cela conserve ton découpage du code dans plusieurs formules OnSelect(), qui peut être plus lisible, mais attention de bien commenter le fonctionnement pour que se soit facilement compréhensible pour les autres citizen dev qui viendraient contribuer sur ton application.
CommentID=Ir6eB2cvgTuBmQT, PostID=QwgjeaKmdvRNPuH
-
Merci Guillaume
et pour ce type d’actions à mener, y a t il une autre fàçon de faire qui serait plus judicieuse ?
le coup d’utiliser des boutons pour y mettre ses codes m’est venu comme çà il y a peu de temps et je me suis aperçu après que d’autres utilisaient cette astuce.
mais après je suis ouvert à toute suggestion qui pourrait être bien plus ‘performante’ et propreSubCommentID=xeeSbDfrI4gojdY, CommentID=Ir6eB2cvgTuBmQT, PostID=QwgjeaKmdvRNPuH
-
Bonjour @JLF,
C’est une pratique courante pour la réutilisabilité du code, on écrit le code sur le OnSelect d’un bouton, pour qu’il puisse n’être écrit qu’une fois et être appelé de plusieurs endroits.
Il est également possible d’utiliser les composants et la fonctionnalité expérimentale des paramètres de propriété pour les composants.
Tu peux jeter un oeil sur cette vidéo qui explique comment tout cela fonctionne (les sous titres traduits en français sont compréhensibles 😉)Dans ton cas, je ne crois pas que cela soit adapté (tu me diras si je me trompe), et je ne vois pas d’autres moyens pour réduire la longueur et améliorer la lisibilité de ton code.
SubCommentID=fbMvTsDF34MgR5B, CommentID=Ir6eB2cvgTuBmQT, PostID=QwgjeaKmdvRNPuH
-
bonjour Guillaume
ca me conforte dans ce que j’ai fait et ma logique de développement en général
j’irai jeter un oeil sur la vidéo car les composants sont également un atout majeur dans PowerApps et dans une possible normalisation
Merci beaucoup !
SubCommentID=jOwI91sj47J6NIy, CommentID=Ir6eB2cvgTuBmQT, PostID=QwgjeaKmdvRNPuH
-
Tu peux lire également ce post de @R3dKap qui explique très bien les différentes possibilités de création des fonctions réutilisables : https://ppfc.fr/ressources/post/creer-des-fonctions-reutilisables-dans-power-apps-8UBo6bCvAyjlac5
SubCommentID=nQ25kkx3SvtwrbD, CommentID=Ir6eB2cvgTuBmQT, PostID=QwgjeaKmdvRNPuH
-
-
@JLF mon avis…
Si je comprends bien, toutes tes opérations de action_RECORD_num_1 jusqu’à action_TICKET_Record_1 dépendent en gros de action_Refresh_1 car tu as besoin de tes données les plus à jour possible pour faire les actions concernées.
Ce que je ferais c’est de sortir le code de action_Refresh_1 (et donc supprimer le bouton correspondant) pour le mettre directement à la place du
Select(action_Refresh_1)
. Car lorsque tu fais appel à la fonction Refresh(), Power Apps attends que le rafraîchissement soit terminé avant de poursuivre le code…Par contre je vois un problème potentiel plus grave dans ton approche : si action_TICKET_Record_1 a besoin des données récupérées par les actions de action_RECORD_num_1 à action_colHAB_get_1, rien ne te garantis que tes données auront été récupérées à temps pour les utiliser dans action_TICKET_Record_1. En effet, utiliser la fonction Select() c’est comme cliquer sur le bouton : là les clics vont s’enchaîner en moins d’une milliseconde, et potentiellement la récupération des données ne sera pas terminée que tu vas déjà créer ton enregistrement dans la table TICKET. Tu me suis ?
Au passage, ton Concurrent() ici va te faire gagner 0,000001ms vu que la seule opération qui est parallélisée avec ton Select() c’est un Set() (qui est ultra rapide). Le Concurrent() a du sens lorsque tu veux par exemple paralléliser des chargements multiples qui peuvent potentiellement prendre du temps.
Du coup, au vu de mes 2 dernières remarques, ce que je te suggère c’est de faire c’est ceci : tu vires tous tes boutons et tu parallélises les chargements des données dont tu vas avoir besoin pour créer ton ticket. Globalement ton code serait donc plutôt structuré ainsi (j’invente un peu hein vu que je connais pas exactement ton modèle de données) :
Set(glbTICKET, Blank());nSet(glbETAPE, "Saisie Ticket");nConcurrent(n Refresh(AGENT),n Refresh(RECORD),n Refresh(TICKET),n Refresh(TECH),n Refresh(HAB)n);nConcurrent(// Là je sais pas si c'est plutôt des LookUp() ou des ClearCollect() que t'as besoinn ClearCollect(colRECORD, Filter(RECORD, ...)),n ClearCollect(colTICKET, Filter(TICKET, ...)),n ClearCollect(colTECH, Filter(TECH, ...)),n ClearCollect(colHAB, Filter(HAB, ...))n);nPatch(TICKET; Defaults(TICKET); {...})
Remarque générale : l’utilisation du Select() pour déclencher du code sur un bouton est utile lorsque l’on veut éviter de dupliquer le code sur un écran où il est utilisé à différent endroits. Mais ATTENTION à ne pas faire un Select() sur un bouton qui est sur un autre écran !!! Ce n’est pas du tout recommandé, voire ça ne marche plus désormais… Pour mutualiser du code il faut plutôt partir sur des fonctions dans des composants comme proposé par @Guillaume RENARD qui fait référence à mon article sur le sujet… 😉
CommentID=pYojEl1fFqKa4d0, PostID=QwgjeaKmdvRNPuH
-
merci pour ton retour explicite R3dKap
tu as tout à fait saisi le déroulement des actions que j’ai à mener.
le souci est que j’avais fait de cette manière (avec Concurrent), mais ma collection colTICKET ne récupérait pas mon numéro de Ticket créé juste avant, une colAGENT qui prenait un peu de temps…
et du coup je mélangeais à la fois du code dans mon bouton de validation et des appels boutons = grosse erreur
mon souci de non attente était prévisible maintenant que j’ai compriset pour l’utilisation du Select, pour cette fois c’est plus pour scinder chaque partie de manière justement à faciliter sa lecture et pouvoir tester individuellement
et oui on ne peut plus appeler un bouton d’un autre écranje m’intéresse beaucoup à la mutualisation via le composant des fonctions mais j’ai eu tres peu de temps à y consacrer pour l’instant et suis resté sur un échec… mais j’y reviendrai c’est sur !
encore merci
CommentID=c9RaPntgqvY34YE, PostID=QwgjeaKmdvRNPuH
-
@JLF le site a pas mal réduit la qualité de ta capture donc je vois pas bien mais peut-être juste une remarque : pourquoi faire un ShowColumns() avec autant de colonnes ? J’ai envie de dire qu’à ce compte-là autant prendre toutes les colonnes. A mon avis faire un ShowColumns() pour garder 80% des colonnes de ta sources de données est plus lent qu’en récupérer direct la totalité…
Et pour réagir à ta problématique “…mais ma collection colTICKET ne récupérait pas mon numéro de Ticket créé juste avant…” :
-
une collection est une photo à un instant t d’une source de données
-
modifier ou créer un élément dans cette source de données n’a absolument aucun impact sur la collection correspondante
-
c’est donc à toi de mettre à jour ta collection pour qu’elle soit bien “synchro” avec ta source de données
T’as 2 solutions :
-
soit tu refais un ClearCollect() pour réalimenter ta collection à partir de ta source de données (pas besoin de rafraîchir cette dernière) -> pas terrible en termes de perf de recharger tout juste parce-qu’un seul élément a été créé ou modifié
-
soit tu appliques à ta collection la même opération (de création ou de modif) qu’à ta source de données
Ce que je fais personnellement :
-
lorsque je crée/modifie un élément dans une source de données à l’aide d’un Patch() je m’assure de bien récupérer l’élément en question en faisant :
locNewOrModifiedItem = Patch(...)
-
ensuite, j’applique la même opération sur la collection correspondante : j’ajoute l’élément locNewOrModifiedItem dans la collection s’il s’agissait d’une création ou je mets à jour l’élément correspondant dans la collection à partir de locNewOrModifiedItem
Par exemple :
locNewItem = Patch(TICKET; Defaults(TICKET); {...});;nCollect(colTICKET; locNewItem)
CommentID=cb8HRlRtMKVthrL, PostID=QwgjeaKmdvRNPuH
-
pour le ShownColumns:
si mes souvenirs sont corrects, j’ai fait ceci pour éviter d’avoir des colonnes système de la liste SHPT sur laquelle je me basepour la collection:
elle n’est remplit qu’une seule fois à la moment de la Validation des saisies mais n’est pas basée sur une remontée de listes SHPT
j’aurais pu utiliser une variable Objet mais la collection est elle utilisable comme source pour une Gallery
le refresh est pour… ben en fait rien 😅 pour cet écran de saisie
j’ai mis ces refresh lundi mais à tort puisque c’est un Flow qui va me cherche le nbr d’enregistrements de ma liste SHPT
je vais enlever cette partie de code inutile.. mercipour ton locNewOrModifiedItem:
ca m’interpelle fortement car je ne savais pas qu’on pouvait encapsulé une fonction comme un PATCH pour après l’injecter dans une collection ! vais me le garder en mémoirecela peut-il servir pour récupérer un résultat éventuellement en erreur ? je dois mettre en place un process d’erreur après que je finisse de vérifier si mon processus de A à Z est correct
SubCommentID=6qBHEHln8FP5L1N, CommentID=cb8HRlRtMKVthrL, PostID=QwgjeaKmdvRNPuH
-
-
Oui tu peux tout à fait utiliser le résultat du Patch() (locNewOrModifiedItem dans mon exemple) pour t’assurer qu’il n’y a pas eu d’erreur :
If(IsBlank(locNewOrModifiedItem); Notify("Erreur"); Notify("OK"))
.Mais le mieux consiste à utiliser la fonction Errors().
De manière générale, faut que t’utilises à fond la doc officielle sur les fonctions qui décrit tout ça hyper bien :
Et sinon, oui bien sûr, tu peux tout à fait utiliser une collection comme source de données d’une galerie… 😉
CommentID=7XKTmRUQlkdXJna, PostID=QwgjeaKmdvRNPuH
-
en tout cas un grand merci pour vos réponses claires
et oui mes recherches sont dans l’ordre :
> doc officielle
> my best friend Google 😂
> forums-blogs-teamsbonne soirée
CommentID=JHXQseOxAhNfEoC, PostID=QwgjeaKmdvRNPuH
Connectez-vous pour répondre.