R3dKap
Expert Power AppsRéponses céées sur le Forum
-
R3dKap
Membre14 décembre 2021 à 10h43 en réponse à: Mode Offline : Limites de stockage et documents@Tanguy Touzard marrant, je vais justement participer aux journées complètes de formation de la MWCP2022 où j’aborderais (entre autres) le sujet du mode déconnecté sous Power Apps 😁 :
https://modern-workplace.pro/agenda-2022/#page-content
Alors pour répondre à tes questions :
- La première chose vraiment importante c’est de bien prendre en compte ce besoin du mode déconnecté dès le début de la conception. Car transformer une application déjà existante pour lui rajouter du mode déconnecté c’est juste l’enfer. Principalement à cause de la manière dont tu gères les données dans l’appli lorsqu’elle inclue le mode déconnecté.
- La gestion des données est donc particulière en mode déconnecté. J’ai fait une grosse appli en mode déconnecté et j’ai choisi de fonctionner comme ceci : la totalité de l’application ne tourne qu’avec des collections locales. Dans les écrans de l’application il n’y a jamais aucun référencement direct aux sources de données (moi c’était du SharePoint), SAUF à la sauvegarde.
- Cela implique qu’il faut impérativement que ton applications puisse tourner avec des volumes de données inférieur à 2000 enregistrements. Parce-que sinon tu t’embarques dans un truc encore plus complexe qu’il ne l’est déjà. Je dis pas que c’est pas impossible mais bon, si on peut l’éviter…
- Dans mon appli, le seul écran qui fait appel aux sources de données c’est l’écran de démarrage qui charge les données nécessaires pour que l’application soit utilisable :
- Il regarde si on est en mode connecté ou pas.
- Si on est connecté, il charge dans des collections toutes les données depuis les sources de données et les RE-stocke en cache local avec SaveData() pour les avoir à dispo au lancement suivant pour le cas où on soit en déconnecté.
- Si on est déconnecté, il charge dans des collections toutes les données depuis le cache local avec LoadData().
- A partir de ce moment-là, vu que tout est chargé dans des collections et que toute ton application ne fait que travailler avec ces collections, ton appli est utilisable que l’on soit en mode connecté ou pas. Et pendant toute son utilisation finalement on s’en fichera pas mal de savoir si on est connecté ou pas, SAUF à la sauvegarde.
- Astuce : pour simuler le mode déconnecté pendant la phase de développement, tu peux mettre un toggle togConnecté quelque part sur un écran que tu définis par défaut à true. Et là l’étape 4.a) tu alimentes une variable gloConnecté avec togConnecté.Value || Connection.Connected. Et c’est gloConnecté que tu testes pour savoir si t’es connecté ou pas.
- Dans l’application, à la sauvegarde :
- Si t’es connecté tu sauvegardes tes collections dans tes datasources
- Ensuite tu sauvegardes toujours tes collections dans le cache local avec le SaveData()
- Attention : si ta source de données génère des données automatiques à la création des enregistrements et que tu en as besoin dans l’appli en mode déconnecté, alors après avoir sauvegardé tes données vers tes datasources, recharge tes collections à partir de tes datasources avant de les sauvegarder dans le cache local.
- Attention : si tu utilises des formulaires dans ton appli et que tu as des champs de type Choice (liste de valeurs), il va falloir que tu les sauvegardes aussi en cache local car la fonction Choices() ne fonctionne que sur de la vraie source de données. Il faudra donc que toi-même tu forces le Items de ces champs-là non pas à du Choices() mais à une collection chargée depuis le cache local.
- Prévois-toi aussi un écran de débogage qui t’affiche facilement en permanence le contenu de tes collections qui sont en cache local. Parce-qu’il n’y a aucun moyen d’y accéder autrement… Et tant qu’à faire, moi j’y avais ajouté la possibilité de supprimer des enregistrements du cache voire carrément de vider une entrée du cache local.
- Tu as de la chance, désormais les fonctions LoadData() et SaveData() fonctionnent en mode web. Auparavant elles ne fonctionnaient que sur des devices mobiles (bien relou pour les test). Assure-toi juste d’avoir activé la fonctionnalité expérimentale correspondante :
Enfin, par rapport aux volumes de données, désormais la limite est celle du device sur lequel l’application tourne (ah : je viens de voir qu’à priori en mode web c’est assez limité… surprenant… à challenger peut-être) :
C’est extrait de la doc de la fonction SaveData() que je t’ai mis ci-dessous…
👉 Ah et par rapport à ta question sur les PDF, je suis pas sûr d’avoir bien compris : tu veux pouvoir rendre des PDF accessibles en mode offline ? Si c’est le cas, je ne crois pas que ce soit possible car le composant lecteur de PDF proposé par Power Apps ne prend en entrée que des URLs. Or, un fichier PDF stocké en local n’aurait pas d’url… A creuser… Je vais réfléchir de mon côté…
Autre resources
- La doc officielle des fonctions SaveData(), LoadData(), ClearData() et Connection.
- Matthew Devaney a fait un p’tit article qui donne les base du concept également, avec un exemple :
Voilou… N’hésite pas à poser d’autres questions si nécessaire… 😉
CommentID=UnAK1rctoRaMZ2o, PostID=4BxZK1snba2M2pC
-
👍 Top ! Bienvenue sur PPFC… Et n’hésite pas à poser tes questions si tu coinces… 😉
CommentID=htJYWDV9qnHA3zQ, PostID=zx0J6jCgy7NBrAQ
-
-
-
-
@Lamia dans ce cas, et au vu de ta réponde aux questions de @Loïc Cimon, la solution la plus simple que j’entrevois pour toi c’est de procéder de la manière suivante…
J’ai supposé dans le code que ta liste des codes postaux et communes s’appelle Communes et que les colonnes s’appellent CodePostal et NomCommune.
Voici les instructions :
- sur ton écran tu mets une seule combo box (en FR, une Zone de liste déroulante, pas une Liste déroulante) appelée ComboBox1
- au-dessus de ta combo box, tu mets un text input (en FR, Entrée de texte) appelé TextInput1
- sur la propriété OnChange de TextInput1, tu mets ceci :
Clear(colCommunes);nIf(n Not(IsBlank(TextInput1.Text)),n If(n IsNumeric(TextInput1.Text),n Collect(n colCommunes,n Filter(n Communes,n StartsWith(n CodePostal,n TextInput1.Textn )n )n ),n Collect(n colCommunes,n Filter(n Communes,n StartsWith(n NomCommune,n TextInput1.Textn )n )n )n )n)n
- définit la propriété IsSearchable de ComboBox1 à false
- sur la propriété Items de ComboBox1 tu mets juste :
colCommunesn
- sur ComboBox1 tu cliques sur le lien Edit de Fields :
- là tu changes le Layout et tu le définis sur Double :
- puis dans Primary text et Secondary text tu mets respectivement tes colonnes de code postal et de commune :
- et enfin, dans la propriété DisplayMode du ComboBox1 tu mets ceci :
If(IsEmpty(colCommunes), DisplayMode.Disabled, DisplayMode.Edit)n
Quelques explications…
En gros, l’idée c’est tout d’abord d’utiliser une combo box en mode double pour afficher à la fois le code postal et la commune dans un seul composant :
Ensuite, on ne peut malheureusement pas utiliser la recherche intégrée à la combo box car il y a plus de 2 000 éléments dans ta liste. Or la fonction Search() (qui est utilisée derrière pour faire cela) n’est pas délégable à SharePoint, c’est à dire que Power Apps ne peut pas dire à SharePoint “Fais la recherche pour moi” il est obligé de la faire lui-même. Et du coup, pour des raisons de performances, Power Apps ne fait la recherche que sur 2 000 enregistrements max.
Du coup, pour contourner ce problème, on va utiliser une autre fonction qui, elle, est délégable à SharePoint : StartsWith().
On mets donc un text input sur l’écran pour permettre à l’utilisateur de saisir son critère de recherche. Or, si on avait fait un StartsWith() sur un champ de type “1000-Bruxelles“, on aurait pu faire la recherche que sur le code postal et si on avait tapé “Brux” il n’aurait rien trouvé puisque la fonction StartsWith() ne compare la chaîne de recherche qu’avec le début de la valeur du champ (comme son nom l’indique d’ailleurs).
C’est la raison pour laquelle dans le gros morceau de code fournit ci-dessus, on regarde si ce que l’utilisateur a saisit est un numérique (alors on fait un StartsWith() sur le code postal) ou une chaîne de caractères (auquel cas on fait un StartsWith() sur la commune).
Le résultat du filtrage des communes avec l’un ou l’autre des StartsWith() est stocké dans une collection locale colCommunes et c’est elle qui alimente la combo box.
Enfin, pour éviter que l’utilisateur n’ouvre la combo box alors qu’il vient de lancer une recherche et que l’on a pas encore les résultats du filtrage, on verrouille la combo box tant qu’il n’y a pas de données dans colCommunes. C’est le but du code que l’on a mit sur la propriété DisplayMode de ComboBox1.
La seule chose à savoir pour l’utilisateur c’est qu’il doit appuyer sur <ENTREE> après avoir saisi son critère de recherche dans TextInput1 pour que cela déclenche la recherche et le filtrage des communes.
Voilà ce que ça donne :
Alors tu remarqueras que j’ai aussi mis une List box (à utiliser à la place de la combo box) qui peut être plus pratique pour afficher directement la liste des communes disponibles. Cela évite de devoir ouvrir la combo box pour voir le résultat du filtrage.
Pour que cela fonctionne bien, il suffit de positionner ses propriétés ainsi :
- Items :
AddColumns(n colCommunes,n "CPCommune",n CodePostal & " - " & NomCommunen)n
- SelectMultiple à false
Puis, choisit bien la colonne CPCommune pour l’affichage des valeurs :
Et histoire de faire plus propre, pour faire en sorte que la liste se vide au moment où on veut faire une nouvelle recherche, définit la propriété OnSelect de TextInput1 à :
Clear(colCommunes)n
Voili voilou… Dis-nous si ça fonctionne chez toi…
SubCommentID=fuxsTPvWHBXWyrE, CommentID=WXr4IG1uohXeSl9, PostID=V61aoLRCRNFfTPX
-
-
R3dKap
Membre7 décembre 2021 à 10h00 en réponse à: Problème mis a jour liste sharepoint en utilisant le control timerVoici mon avis… La solution avec le timer peut effectivement fonctionner, tel que le montre @Didier Gbenou.
Cependant, il y a une solution beaucoup plus simple : construire une collection avec les enregistrements souhaités et faire un seul Patch(). En effet, la fonction Patch() est souvent utilisée pour créer ou mettre à jour UN enregistrement. Mais on oublie trop souvent qu’elle peut aussi être utilisée en lui fournissant un ensemble d’enregistrements dans une collection.
Donc, en gros, ce que tu peux faire c’est quelque chose comme ceci :
ClearCollect(colGestionList; {});;nClear(colGestionList);;nForAll(n Sequence(n DateDiff(n DatePickerDebut.SelectedDate;n DatePickerFin.SelectedDaten ) + 1n );n Collect(n colGestionList; n {n Staff: ComboBoxStaff.Selected;n Assiduite: ComboBoxAssiduite.Selected;n DateP: DateAdd(n DatePickerDebut.SelectedDate;n Value - 1n )n }n )n);;nPatch(GestionList; Defaults(GestionList); colGestionList);; n
Je te laisse remplacer les noms des contrôles que j’y ai mis par les tiens… 😉
Autre remarque : je ne vois pas trop l’intérêt de ton formulaire ici puisque tu n’utilises pas le SubmitForm(). Tu pourrais tout aussi bien mettre sur ton écran :
- une ComboBox pour le Staff avec Choices(GestionList.Staff) dans le Items (attention de bien positionner ensuite les propriétés DisplayFields et SearchFields)
- une ComboBox pour l’Assiduité avec Choices(GestionList.Assiduite) dans le Items (attention de bien positionner ensuite les propriétés DisplayFields et SearchFields)
- un DatePicker pour la date de début
- un DatePicker pour la date de fin
Et utiliser ensuite le code ci-dessus… 😊
CommentID=95e9iLM4235LlRb, PostID=wdLihsBfRSa3Svt
-
-
-
R3dKap
Membre29 novembre 2021 à 12h07 en réponse à: Récupération du mois d'une date en français à partir d'un flow.Et voilàaaaa @Youcef DOUMANDJI… 😉
CommentID=cIufklywc59mORO, PostID=hFq0E3rgJ39ffkd
-
@Alain Pujol une petite remarque pour compléter : tu peux directement enlever la partie Galerie.Selected.Nom qui est dans le “sinon” de ton If(!IsBlank(ChoixNom)…). En effet, remettre dans un champ la même valeur qu’elle contient revient à ne rien faire… 😉
Et du coup, tu pourrais même sortir ton If() du Patch() pour conditionner le Patch() lui-même (si tu ne mets pas à jour d’autres colonnes de ta liste dans ce Patch().
SubCommentID=RkMwqATWCCg91aY, CommentID=IlGwCfkM0D53vDt, PostID=1GRnX5Z9htknXOW
-
R3dKap
Membre9 décembre 2021 à 10h32 en réponse à: Problème mis a jour liste sharepoint en utilisant le control timer@Thika voici le code corrigé :
ClearCollect(n colGestionList; Defaults(GestionList)n);;nClear(colGestionList);;nForAll(n Sequence(n DateDiff(n DatePickerDebut.SelectedDate;n DatePickerFin.SelectedDaten ) + 1n );n Collect(n colGestionList;n Defaults(GestionList)n );;n Update(n colGestionList;n Last(colGestionList);n {n Staff: ComboBoxStaff.Selected;n Assiduite: ComboBoxAssiduite.Selected;n DateP: DateAdd(n DatePickerDebut.SelectedDate;n Value - 1n )n }n )n);;nPatch(GestionList; colGestionList);;n
SubCommentID=XyUoFfJ9aDEfji3, CommentID=zsuO6Z52HO0Vqef, PostID=wdLihsBfRSa3Svt
-
R3dKap
Membre8 décembre 2021 à 10h29 en réponse à: Problème mis a jour liste sharepoint en utilisant le control timer@Thika Est-ce que tu peux m’envoyer une capture du code où on voit l’erreur soulignée en rouge ? Ca me permettra de voir quelle partie de la formule est en erreur. En général il y a une partie de la formule qui est un peu plus rouge que le reste. Si tu survoles avec ta souris cette partie très rouge pour voir le message qui s’affiche dans l’infobulle et me le transmettre également.
Astuce : pense à renommer tes datacards pour qu’on puisse savoir ce qu’ils portent comme donnée… 😉
SubCommentID=K12vBMSr0NmEi8g, CommentID=zsuO6Z52HO0Vqef, PostID=wdLihsBfRSa3Svt
-
Tout simplement avec la fonction Filter()… 😉
Voici sa documentation :
SubCommentID=6yeEb6B1vQBgWIU, CommentID=upAnOVtlC247dV6, PostID=weSqscm557mue47
-
R3dKap
Membre24 novembre 2021 à 9h51 en réponse à: Je suis entrain de construire un flux et j'ai ce message d'avertissement. Je cherche une solution:@Didier Gbenou a raison : dans ton bloc Définir une variable il te suffit de convertir ton champ NextNumber en entier à l’aide de la fonction int().
SubCommentID=Ga8MP17LBYNL06y, CommentID=XwNYmOyc9P3zJer, PostID=KkA1G9Jnkliq8EW