R3dKap
Expert Power AppsRéponses céées sur le Forum
-
@Philippe CULOT sauf erreur de ma part, je crois qu’en fait il te manque le “=” en début de formule, comme sur l’exemple à la fin du post de @Didier… 😉
CommentID=iFNHDYGrF41JZ0O, PostID=xzHIOqVIlwj3bKA
-
Quelques explications donc sur cette formule qui s’occupe de faire le filtrage sur les pilotes :
Clear(colSaaraData);nForAll(n cbxPilotes.SelectedItems As SelItem,n ForAll(n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n (IsBlank(cbxProcessus.Selected) || CODEPROCESSUS.Value = cbxProcessus.Selected.Value) && SelItem.Claims in PilotesClaimsn ) As PiloteItem,n If(n Not(PiloteItem.ID in colSaaraData.ID),n Collect(n colSaaraData,n PiloteItemn )n )n )n)
C’est le filtre sur les pilotes est à choix multiples qui complique tout évidemment. Cela nous oblige à boucler sur la liste des
cbxPilotes.SelectedItems
pour commencer.Pour chaque pilote qui figure dans cette table, il faut aller chercher les données correspondantes dans la liste, soit quelque chose comme ceci :
ForAll(n cbxPilotes.SelectedItems As SelItem,n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n SelItem.Claims in PilotesClaimsn )n...
Remarque : la structure des données de la combo box cbxPilotes étant complexe (type Personne) à plusieurs colonnes on ne peut pas utiliser l’opérateur IN, ça ne marche pas :
ForAll( // ### Ceci ne marche pas !!!n cbxPilotes.SelectedItems As SelItem,n Filter(n SAARA,n SelItem in PILOTEADn )n...
C’est pour cette raison qu’on est obligé de rajouter à la source de données SAARA une colonne PilotesClaims avec le AddColumns() pour n’avoir dans cette colonne que les valeurs de Claims pour les pilotes sélectionnés :
AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn)
En imaginant que pour une ligne de SAARA j’ai 3 pilotes Pilote1, Pilote2 et Pilote3 dans la colonne PILOTEAD, la formule ci-dessus produit ce résultat :
Et du coup, là sur la colonne PilotesClaims je peux utiliser l’opérateur IN. Et donc je peux écrire ceci :
ForAll(n cbxPilotes.SelectedItems As SelItem,n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n SelItem.Claims in PilotesClaimsn )n...
⛔ ATTENTION : le AddColumns() va faire appel au connecteur SharePoint pour ramener les données de la liste SAARA avant de lui ajouter la colonne. Or, quelque soit le connecteur, Power Apps ne ramènera jamais plus de 2000 lignes (paramètre de ton application qu’il faut passer de 500 à 2000). Conséquence : tout ce qu’on a construit depuis le début pour faire ce filtrage ne fonctionnera que si ta liste SAARA a moins de 2000 lignes.
Bref… La problématique suivante à laquelle on est confronté c’est qu’un pilote peut être sur plusieurs lignes de la liste SAARA. Ca veut que lors d’un premier passage du ForAll() ci-dessous je vais ramener les lignes 12, 27, 349 et 618 ; et lors d’un 2è passage je vais ramener une deuxième fois la ligne 349. Je me retrouve donc avec des doublons dans le résultat de mon filtrage !!!
Conséquence, il faut que je conditionne l’ajout d’une ligne à ma collection colSaaraData au fait qu’elle n’y est pas déjà. Je suis donc obligé de faire une 2è boucle à l’intérieur de la première pour que je puisse mettre en place cette condition :
ForAll(n cbxPilotes.SelectedItems As SelItem,n ForAll(n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n SelItem.Claims in PilotesClaimsn ) As PiloteItem,n If(n Not(PiloteItem.ID in colSaaraData.ID),n Collect(n colSaaraData,n PiloteItemn )n )n )n)
Et pour terminer, il ne faut pas oublier qu’il se peut que j’ai sélectionné un filtre dans la combo box cbxProcessus avant de filtrer sur les pilotes. Il faut donc que j’en tienne compte que je fais mon filtre ici sur les pilotes, d’où l’ajout de la partie :
(IsBlank(cbxProcessus.Selected) || CODEPROCESSUS.Value = cbxProcessus.Selected.Value)
Et donc, la formule globale :
Clear(colSaaraData);nForAll(n cbxPilotes.SelectedItems As SelItem,n ForAll(n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n (IsBlank(cbxProcessus.Selected) || CODEPROCESSUS.Value = cbxProcessus.Selected.Value) && SelItem.Claims in PilotesClaimsn ) As PiloteItem,n If(n Not(PiloteItem.ID in colSaaraData.ID),n Collect(n colSaaraData,n PiloteItemn )n )n )n)
Voilou… Je me rends compte que c’est très compliqué à expliquer comme ça par écrit.
NOTE IMPORTANTE : si jamais ta liste dépasse les 2000 lignes, la seule solution pour s’en sortir c’est d’obliger l’utilisateur à filtrer D’ABORD sur le processus AVANT de filtrer sur les pilotes, tout en s’assurant que le premier filtrage sur le processus ne ramène pas plus, quant à lui, de 2000 lignes.
CommentID=UDFzTeuzTofokdW, PostID=OwMnA3HFeAv42u0
-
@S petit retard dans la livraison… 🙏
Alors voilà les instructions…
Pour faire mon test j’ai créé des listes qui ont exactement les mêmes colonnes que toi. Mes 2 listes déroulantes s’appellent cbxProcessus et cbxPilotes. Ma galerie s’appelle galSaara et j’ai aussi un toggle nommé togFilterData.
Pour commencer, les 2 listes déroulantes sont alimentées comme ceci :
cbxProcessus.Items = Choices(SAARA.CODEPROCESSUS)nncbxPilotes.Items = Choices(SAARA.PILOTEAD)
Pour rappel, la structure d’un champ de type Personne est la suivante :
{n DisplayName: Blank();n Claims: "i:0#.f|membership|" & Lower(User().Email);n Department: Blank();n Email: Blank();n JobTitle: Blank();n Picture: Blank()n}
Pour la combo box cbxPilotes, j’affiche le champ DisplayName :
cbxPilotes.DisplayFields = ["DisplayName"]ncbxPilotes.SearchFields = ["DisplayName"]
Et bien sûr j’y ai activé la sélection multiple :
cbxPilotes.SelectMultiple = true
Ensuite, pour différentes raison que je vais essayer d’expliquer plus loin, je ne filtre pas la galerie directement sur la combo box des pilotes. Au lieu de cela, lorsque je change ma sélection de pilotes, je construis une collection colSaaraData avec les données filtrées.
Cette collection je la remplis dans l’événement OnChange du toggle togFilterData :
Clear(colSaaraData);nForAll(n cbxPilotes.SelectedItems As SelItem,n ForAll(n Filter(n AddColumns(n SAARA,n "PilotesClaims",n PILOTEAD.Claimsn ),n (IsBlank(cbxProcessus.Selected) || CODEPROCESSUS.Value = cbxProcessus.Selected.Value) && SelItem.Claims in PilotesClaimsn ) As PiloteItem,n If(n Not(PiloteItem.ID in colSaaraData.ID),n Collect(n colSaaraData,n PiloteItemn )n )n )n)
Et donc sur la combo box cbxPilotes, dès lors qu’il y a un changement, je bascule une variable locale locFilterData qui va elle-même déclencher le OnChange du toggle togFilterData :
cbxPilotes.OnChange = UpdateContext({locFilterSaara: Not(locFilterSaara)})nntogFilterData.Default = locFilterSaara
Le OnChange tu toggle togFilterData qui filtre les données doit également être déclenché si je change de processus dans la liste déroulante cbxProcessus :
If(n Not(n IsEmpty(cbxPilotes.SelectedItems)n ), n UpdateContext({locFilterSaara: Not(locFilterSaara)})n)
On peut maintenant définir les éléments de la galerie. Pour cela, on considère 2 cas de figure : il n’y a aucun critère sur les pilotes et je filtre uniquement sur le processus ; dans tous les autres cas je dois filtrer à la fois sur les processus et les pilotes. Dans ce dernier cas, comme le travail est fait par le toggle, je me contente d’utiliser la collection qui en résulte.
Voici donc le code du Items de la galerie :
If(n IsBlank(cbxPilotes.Selected), n Filter(n SAARA, n IsBlank(cbxProcessus.Selected) || CODEPROCESSUS.Value = cbxProcessus.Selected.Value),n colSaaraDatan)
Voilà ce que ça donne au final :
Je te mets ci-joint le package de l’application que j’ai faite. Comme j’ai utilisé les mêmes colonnes que toi, il devrait te suffire de supprimer mes 2 listes et que tu mettes les 2 tiennes pour que l’appli marche de ton côté. Sinon, n’hésite pas à revenir vers moi.
Je vais expliquer dans un autre post ci-dessous la formule de filtrage du toggle…
CommentID=MSZ0BZgSh1PIafy, PostID=OwMnA3HFeAv42u0
-
Cher client,
Votre commande est prête et sa livraison est cours…
Livraison prévue le 31/01 dans la journée…
😉
CommentID=5eZYqWYAH7u4H7n, PostID=OwMnA3HFeAv42u0
-
D’accord… Alors à ce moment-là la solution décrite par @Pierre Bourdial était la bonne : utiliser le StartScreen pour définir quel est le premier écran que l’application doit afficher.
Mais avant ça il faut que tu aies un moyen pour ton application de différencier un admin d’un utilisateur classique. Par exemple tu peux avoir une liste SharePoint appelée Administrateurs dans laquelle tu as une colonne Admin de type Personne où tu renseigneras les utilisateurs qui sont des administrateurs pour cette application.
A ce moment-là, sur l’objet App de ton application, tu choisis la propriété StartScreen :
Et tu y mets ce code :
If(n IsBlank(n LookUp(n Administrateurs; n Admin.Email = User().Emailn )n 'Ecran Formulaire'n 'Ecran Admin';n)
En gros, avec le LookUp() on recherche dans la liste des Administrateurs s’il y a un utilisateur qui correspond à l’utilisateur actuellement connecté, identifié avec la fonction User(). Si on n’en trouve pas (IsBlank()), c’est que l’utilisateur connecté n’est pas un administrateur et donc le premier écran que l’application va afficher c’est celui du formulaire. Dans le cas contraire, on a trouvé un administrateur dans la liste et donc c’est l’écran des admins qui est affiché.
Est-ce que cela réponds à ton besoin ?
Dis-nous si tu y arrives ou pas… Si tu bloques, pense à nous mettre une capture d’écran du problème en nous donnant le maximum d’informations.
CommentID=6PBeTSfAQeCJ1xF, PostID=PUQn5fvB5eZ9EWm
-
Merci @Pierre Bourdial je l’ai rajouté dans le post…
CommentID=vfnjwDEZOhwSGa0, PostID=rwcsbJLxJTiTqi0
-
Du coup est-ce que tu peux me lister précisément les noms de tes listes et de tes colonnes (noms techniques) stp, sous ce format-ci par exemple :
Activites (nom dans l’url)
-
Titre (code de l’activité)
-
scLibelle (texte simple)
GestionActivites (nom dans l’url)
-
Titre (code de l’activité, ou autre)
-
scActivite (lookup)
-
scSousActivite (texte simple)
-
scResponsable (texte simple)
-
scResponsableAD (personne)
-
scEtat (choix)
Merci. Comme ça on se comprendra beaucoup mieux par la suite…
CommentID=BuZle2nuao5SUee, PostID=OwMnA3HFeAv42u0
-
-
Colonne scResponsable
En réalité, ce que j’essayais de t’expliquer dans un de mes posts précédents, c’est que plutôt que de renseigner ta colonne de type Personne à la main avec les bonnes personnes en fonction de ce que tu as dans ton fichier Excel, il y aurait moyen de faire ça en une seule opération. J’explique…
Si dans ton fichier tu as dans ta colonne des responsables une cellule de texte dans laquelle tu as une valeur “Michel DURAND” et que dans l’AD de ton entreprise tu as bien un Michel DURAND (écrit pareil), si tu édites ta liste SharePoint en mode grille et que tu copies/colles/ “Michel DURAND” de ta cellule Excel vers la cellule de ta liste SharePoint dans la colonne de type Personne, il va te le transformer immédiatement en vraie personne Michel DURAND de ton AD.
Et mieux encore. En supposant que ta colonne de type Personne soit bien multi-valuée, si dans ta cellule Excel tu as “Michel DURAND;Pierre PAUL” et que tu as bien 2 comptes qui s’appellent comme ça dans l’AD, tu peux aussi les copier/coller dans ta liste en mode grille et il les transformeras tous les 2 en vrais comptes AD.
Du coup, il “suffirait” que tu mettes bien ton fichier Excel au propre (en faisant peut-être quelques chercher/remplacer) pour avoir les vrais bons noms des personnes, bien séparés avec des points-virgules et tu pourrais les copier/coller en une seule fois dans ta liste.
Tu me suis ?
Mais t’as déjà fait le boulot donc, avançons… 😉
CommentID=FUp5hhbMYYVjedn, PostID=OwMnA3HFeAv42u0
-
Colonne scActivite
Pour répondre à ta question sur la colonne scActivite (attention “sc” pas “ss” et pas d’accent -> oui je suis hyper pointilleux sur la terminologie en général 😁)…
Lorsque tu crées une colonne de lookup (lookup = recherche en français dans SharePoint -> à retenir), la 2è liste déroulante que tu remplis dans les caractéristiques de la colonne représente le champ lié dans la liste cible, c’est à dire celui qui sera affiché dans la liste déroulante lorsque tu éditeras ou créeras un élément dans liste SharePoint via le formulaire natif (ou d’ailleurs celle d’un contrôle formulaire dans une application Power Apps).
Mais tu peux le changer si tu veux et pointer plutôt sur la colonne Titre pour afficher le libellé de l’activité en lieu et place du code. C’est juste que parfois les libellés peuvent être un peu long et que dans une liste déroulante ça peut ne pas être terrible visuellement…
A partir de maintenant, comme tu vas utiliser des lookups, retiens une seule chose hyper importante… Une colonne lookup est ce que l’on appelle “une colonne de type complexe” car elle a une structure interne plus complexe que simplement du texte, un nombre ou une date.
La structure d’un lookup est la suivante :
{n Id: <identifiant numérique>;n Value: <valeur>n}
La colonne Id représente l’identifiant SharePoint de l’élément dans la liste cible et la colonne Value la valeur du champ lié dans la liste cible (dont je parle précédemment).
Exemple…
Dans la liste Activités tu as ceci :
Dans la liste GestionActivites tu as ceci :
Eh bien pour la ligne encadrée en rouge, tu auras en interne dans ta colonne scActivite la valeur suivante :
{n Id: 2;n Value: "PM233"n}
Et si je venais à changer le champ lié de ma colonne scActivite pour le faire pointer sur la colonne scLibelle de la liste Activites, j’aurais ça :
{n Id: 2;n Value: "Piloter et gérer le contrôle"n}
Voilà… Là t’as les bases du fonctionnement des lookups…
Je te fais un autre post juste après sur le sujet de la colonne scResponsable…
CommentID=DEPdWNDkfvOBzTJ, PostID=OwMnA3HFeAv42u0
-
LOL… Pas de soucis… Voici comment faire :
Sur ton icône Hamburger :
Set(varAnimateMenu, false);nSet(varAnimateMenu, true);nSet(varMenuOpen, Not(varMenuOpen));
Sur ton ControlAnimator :
Animate = varAnimateMenunReverse = varMenuOpen
Voilà… Ca fonctionne avec ça chez moi…
CommentID=rLXuyothHwS48wo, PostID=HCjpNAUGMo4ZUDA
-
@S je te confirme que pour que je puisse avancer maintenant, une fois que tu auras terminé les différentes étapes ci-dessus, c’est que l’on règle la problématique de la colonne des responsables.
Quel est le type de la colonne ? Et comment l’as-tu rendu multi-valeurs ?
Info très intéressante : on pourrait assez facilement créer une vraie colonne de type Personne multi-valeurs et copier/coller les noms des responsables que tu as actuellement dans ton tableau Excel. Il faut simplement que les noms des personnes dans ton fichier Excel correspondent aux noms des personnes dans l’AD de ton tenant, dans Microsoft 365. Et il suffit de les séparer par un point-virgule pour en mettre plusieurs.
Et là on serait nickel en termes de structuration de nos données.
On en rediscute…
CommentID=TAUYdNxsDpPwWof, PostID=OwMnA3HFeAv42u0
-
Merci @Lamia. Je vais essayer de reformuler pour voir si j’ai bien compris.
Tu as créé une application Power Apps dans laquelle il y a (au moins) 2 écrans : 1 écran pour les admins, un écran pour les utilisateurs.
Sur l’écran pour les utilisateurs il y a un formulaire qu’ils doivent remplir.
Sur l’écran des Admins il y a un bouton qui permet d’envoyer un email aux utilisateurs avec un lien dans cet email. Lorsqu’un utilisateur clique sur le lien de cet email il doit arriver directement dans l’application sur l’écran du formulaire.
Est-ce que c’est ça ?
CommentID=82eQ2mslQKAEr7A, PostID=PUQn5fvB5eZ9EWm
-
@S assure-toi de bien revenir sur mon message précédent ci-dessus passke j’ai galéré à le sauvegarder. J’ai dû m’y reprendre à plusieurs fois… 😉
CommentID=LzcKf51VoewIbXz, PostID=OwMnA3HFeAv42u0
-
Aaaah… Voilàaaaa… 😀 On arrive au cœur du problème… 😉
De manière générale, la manière dont tu structures tes données est absolument capital pour que ton application soit non seulement facile à réaliser mais également pour que ses performances et l’expérience de tes utilisateurs soient bonnes…
Alors, je te recommande vivement de prendre quelques minutes (pas plus) pour construire de “vraies” listes SharePoint avec des liens entre elles pour qu’elles représentent la réalité et que ça te facilite les choses par la suite.
Cela impliquera bien sûr que tu te mettes sérieusement au LookUp() 😉. Mais tu as tout intérêt à t’y coller car c’est réellement la bonne pratique. Et je serais là pour t’aider au besoin.
Donc… Voici comment je te suggère de procéder…
Créer la liste des activités
-
Dans ton fichier Excel crée un onglet appelé Activités qui va servir à créer la liste des activités
-
Dans cet onglet copie uniquement les colonnes CODE_ACT et LIB_ACT de ton tableau global
-
Renomme tes colonnes CODE_ACT en Titre et LIB_ACT en scLibelle (attention pas d’accents, pas d’espaces) :
-
Nomme ce tableau Excel Activités :
-
Utilise la fonction de suppression de doublons d’Excel pour ne plus avoir de doublons dans cette liste d’activités (ne coche que la colonne Titre pour éviter de conserver des doublons parce-que leurs libellés ne seraient pas rigoureusement identiques) :
-
Sauvegarde ton fichier Excel
-
Utilise la création de liste SharePoint basée sur un fichier Excel pour créer une liste avec toutes les activités (choisi bien le tableau Activités et positionne les types de colonnes ainsi :
-
Appelle ta liste Activites (pas d’accents non plus) et clique sur Créer :
Adapter ta liste globale
Maintenant on s’occupe de ta liste globale. Je te propose de la réimporter après l’avoir retouchée ainsi dans Excel :
-
Supprime la colonne LIB_ACT
-
Renomme tes colonnes…
-
Renomme CODE_ACT en Titre
-
Renomme SOUS_ACT en scSousActivite (sans accents -> note : on essaie toujours de donner des noms de colonnes très parlant quitte à ce qu’ils soient un peu longs)
-
Renomme AGENT en scAgent (ou scResponsable car tu parlais de “responsable” au début de ton post)
-
Renomme ETAT en scEtat
-
-
Sauvegarde ton fichier
-
Importe ce tableau Excel dans SharePoint en définissant les types de colonnes comme ci-dessous…
-
Titre -> Titre
-
scSousActivite -> Une ligne de texte (sauf si tu veux en faire un choix, mais les libellés m’ont l’air assez longs)
-
scAgent -> là idéalement il faudrait une colonne de type Personne pour qu’elle représente vraiment le compte M365 de la personne dans l’AD, mais je pense que l’import de liste Excel ne supporte pas ce type de données -> effectivement, je viens de vérifier ; mais y’a un sujet à creuser là, passke le jour où tu voudrais filtrer ta liste sur l’agent… 😬 ; tiens et d’ailleurs comment as-tu fait de cette colonne une colonne à choix multiples ? Tu l’as importée en tant que Choix puis t’as modifié la colonne pour la rendre multi-valeurs ?) ; donc là je te laisse choisir pour que t’arrives à avoir ta colonne à choix multiple
-
scEtat -> Choix
-
-
Importe ta liste et nomme-là comme tu veux (moi je l’ai appelée GestionActivites) mais sans accents et sans espaces
-
Va dans les paramètres de ta liste et crée une nouvelle colonne nommée scActivite de type Recherche -> la page se recharge
-
Ensuite positionne ses caractéristiques ainsi (attend que la page se recharge encore une fois que tu auras choisi ta liste dans la première liste déroulante) :
-
Enregistre la colonne
-
Va sur l’affichage de la liste et déplace ta colonne scActivite pour la mettre entre Titre et scSousActivite :
-
Clique sur Modifier en mode grille et copie/colle (CTRL-C/CTRL-V) toutes les données de la colonne Titre vers la colonne scActivite comme si tu étais dans Excel :
Voââââlà ! Là on est prêt pour commencer à bosser dans Power Apps… Dis-moi quand c’est bon de ton côté et on continue…
CommentID=oVQA82BjtmXjMnv, PostID=OwMnA3HFeAv42u0
-
-
Je vois… Mais du coup de votre côté, c’est-à-dire du côté de ceux qui gèrent aujourd’hui les activités, pourquoi n’avoir pas décidé malgré tout d’en faire une liste ? Pour éviter l’utilisation de lookups que vous ne maîtrisez peut-être pas encore bien aujourd’hui ?
Désolé de creuser encore mais, de mon point de vue, construire une liste déroulante sur la base d’un champ texte n’a pas vraiment de sens. Une liste déroulante implique pour moi un référentiel quelque part (que soit un Choice ou une liste dédiée).
Je sais pas, peut-être si tu me donnes quelques exemples je comprendrais mieux.
En attendant je vais déjà attaquer le pb…
CommentID=D3993ZYiHo9hW6v, PostID=OwMnA3HFeAv42u0