Les formules nommées (Formulas) dans Power Apps Canvas
Présentation générale
Les formules nommées constituent une fonctionnalité permettant de définir des calculs réutilisables au niveau de l’application. Contrairement aux variables qui stockent une valeur à un instant donné, les formules nommées sont recalculées automatiquement chaque fois que leurs dépendances changent, à l’image des formules dans Excel.
Cette fonctionnalité est accessible via l’objet App.Formulas dans le panneau de propriétés de l’application.
Différence fondamentale avec les variables
| Caractéristique | Variable (Set) | Formule nommée |
| Définition | Impérative (action) | Déclarative |
| Mise à jour | Manuelle via Set() | Automatique |
| Moment du calcul | À l’exécution de Set() | À chaque changement de dépendance |
| Emplacement | N’importe où (OnSelect, OnVisible, etc.) | App.Formulas uniquement |
| Réactivité | Non réactive | Réactive |
Exemple comparatif
Avec une variable :
// Dans OnVisible ou OnSelect
Set(varTotalTTC, varTotalHT * 1.20)
// Problème : si varTotalHT change ailleurs, varTotalTTC n'est pas recalculéAvec une formule nommée :
// Dans App.Formulas
frmTotalTTC = frmTotalHT * 1.20;
// Avantage : frmTotalTTC est recalculé automatiquement dès que frmTotalHT changeSyntaxe et déclaration
Les formules nommées se déclarent dans la propriété App.Formulas accessible en sélectionnant l’objet App dans l’arborescence.
Syntaxe de base
NomFormule = Expression;Règles syntaxiques
- Chaque formule se termine par un point-virgule
- Les noms de formules doivent être uniques
- Les formules peuvent référencer d’autres formules nommées
- L’ordre de déclaration n’a pas d’importance (résolution automatique des dépendances)
Exemple de déclaration multiple
// Formules de configuration
frmTauxTVA = 0.20;
frmSeuilAlerte = 100;
frmDevise = "€";
// Formules calculées
frmTotalHT = Sum(colPanier, Prix * Quantite);
frmMontantTVA = frmTotalHT * frmTauxTVA;
frmTotalTTC = frmTotalHT + frmMontantTVA;
// Formule conditionnelle
frmMessageAlerte = If(
frmTotalTTC > frmSeuilAlerte,
"Montant élevé : validation requise",
""
);
// Formule formatée
frmAffichageTotal = Text(frmTotalTTC, "#,##0.00") & " " & frmDevise;Types de formules nommées
Formules scalaires
Retournent une valeur unique (texte, nombre, booléen, date).
frmUtilisateurActuel = User().FullName;
frmDateAujourdhui = Today();
frmEstWeekend = Weekday(Today()) in [1, 7];
frmNombreClients = CountRows(colClients);Formules de table
Retournent une table complète, utile pour centraliser des filtres ou transformations.
frmClientsActifs = Filter(colClients, Statut = "Actif");
frmVentesTriees = Sort(
Filter(colVentes, Annee = Year(Today())),
Montant,
SortOrder.Descending
);
frmTopProduits = FirstN(
Sort(colProduits, NombreVentes, SortOrder.Descending),
10
);Formules d’enregistrement
Retournent un enregistrement unique.
frmParametresApp = {
Theme: "Clair",
Langue: "fr-FR",
NombreResultatsParPage: 20,
ModeDebug: false
};
frmMeilleurVendeur = First(
Sort(colVendeurs, ChiffreAffaires, SortOrder.Descending)
);Formules avec tables statiques
Permettent de définir des données de référence.
frmListeStatuts = Table(
{ Code: "BRO", Libelle: "Brouillon", Couleur: RGBA(150,150,150,1) },
{ Code: "ENC", Libelle: "En cours", Couleur: RGBA(0,120,212,1) },
{ Code: "TER", Libelle: "Terminé", Couleur: RGBA(16,124,16,1) },
{ Code: "ANN", Libelle: "Annulé", Couleur: RGBA(168,0,0,1) }
);
frmJoursSemaine = Table(
{ Numero: 1, Nom: "Dimanche", Abrege: "Dim", EstOuvre: false },
{ Numero: 2, Nom: "Lundi", Abrege: "Lun", EstOuvre: true },
{ Numero: 3, Nom: "Mardi", Abrege: "Mar", EstOuvre: true },
{ Numero: 4, Nom: "Mercredi", Abrege: "Mer", EstOuvre: true },
{ Numero: 5, Nom: "Jeudi", Abrege: "Jeu", EstOuvre: true },
{ Numero: 6, Nom: "Vendredi", Abrege: "Ven", EstOuvre: true },
{ Numero: 7, Nom: "Samedi", Abrege: "Sam", EstOuvre: false }
);Cas d’usage recommandés
Centralisation des calculs métier
// Règles de calcul centralisées
frmTauxRemiseStandard = 0.05;
frmTauxRemisePremium = 0.15;
frmSeuilPremium = 1000;
frmTauxRemiseApplicable = If(
frmTotalHT >= frmSeuilPremium,
frmTauxRemisePremium,
frmTauxRemiseStandard
);
frmMontantRemise = frmTotalHT * frmTauxRemiseApplicable;
frmTotalApresRemise = frmTotalHT - frmMontantRemise;Filtres réutilisables
// Filtres centralisés utilisables dans plusieurs galeries ou contrôles
frmCommandesEnAttente = Filter(
colCommandes,
Statut = "En attente" And DateCommande >= DateAdd(Today(), -30, TimeUnit.Days)
);
frmProduitsEnRupture = Filter(
colProduits,
Stock <= SeuilAlerte
);
frmTachesUrgentes = Filter(
colTaches,
Priorite = "Haute" And DateEcheance <= DateAdd(Today(), 7, TimeUnit.Days)
);Données de configuration
frmConfigApp = {
NomApplication: "Gestion des ventes",
Version: "2.1.0",
Environnement: "Production",
UrlApi: "https://api.monentreprise.fr/v2",
DelaiTimeout: 30,
NombreMaxResultats: 500
};
// Utilisation
frmConfigApp.NomApplication
frmConfigApp.UrlApiTraductions et libellés
frmLangue = "FR";
frmLibelles = If(
frmLangue = "FR",
{
BtnValider: "Valider",
BtnAnnuler: "Annuler",
MsgErreur: "Une erreur est survenue",
MsgSucces: "Opération réussie"
},
{
BtnValider: "Submit",
BtnAnnuler: "Cancel",
MsgErreur: "An error occurred",
MsgSucces: "Operation successful"
}
);
// Utilisation dans un bouton
Text: frmLibelles.BtnValiderDépendances et ordre d’évaluation
Les formules nommées gèrent automatiquement leurs dépendances. L’ordre de déclaration n’a aucune importance.
Exemple de chaîne de dépendances
// Ces formules peuvent être déclarées dans n'importe quel ordre
frmTotalTTC = frmTotalHT + frmMontantTVA;
frmMontantTVA = frmTotalHT * frmTauxTVA;
frmTotalHT = Sum(colPanier, PrixUnitaire * Quantite);
frmTauxTVA = 0.20;
// Power Apps résout automatiquement :
// 1. frmTauxTVA (aucune dépendance)
// 2. frmTotalHT (dépend de colPanier)
// 3. frmMontantTVA (dépend de frmTotalHT et frmTauxTVA)
// 4. frmTotalTTC (dépend de frmTotalHT et frmMontantTVA)Détection des références circulaires
Power Apps détecte et signale les références circulaires.
// Erreur : référence circulaire
frmA = frmB + 1;
frmB = frmA + 1;Limitations et contraintes
Ce que les formules nommées ne peuvent pas faire
| Limitation | Alternative |
| Appeler des fonctions comportementales (Collect, Navigate, Set, etc.) | Utiliser OnSelect, OnChange, etc. |
| Modifier des données | Utiliser des actions dans les contrôles |
| Être modifiées pendant l’exécution | Utiliser des variables pour les valeurs dynamiques |
| Accéder au contexte d’un écran spécifique | Utiliser des variables contextuelles |
Fonctions non disponibles dans App.Formulas
// Ces fonctions ne peuvent PAS être utilisées dans App.Formulas
Collect()
ClearCollect()
Remove()
Patch()
Set()
UpdateContext()
Navigate()
Back()
Notify()
Launch()Contournement pour les données modifiables
Combinez formules nommées et collections :
// Dans App.OnStart
ClearCollect(colPanier, Blank())
// Dans App.Formulas (calcul réactif sur la collection)
frmTotalPanier = Sum(colPanier, Prix * Quantite);
frmNombreArticles = CountRows(colPanier);
frmPanierVide = IsEmpty(colPanier);Bonnes pratiques
Convention de nommage
// Préfixer les formules nommées pour les distinguer des variables
frmNomFormule // Formule nommée
varNomVariable // Variable globale
locNomVariable // Variable contextuelle
colNomCollection // CollectionOrganisation par catégorie
// ═══════════════════════════════════════════════════════
// CONFIGURATION
// ═══════════════════════════════════════════════════════
frmTauxTVA = 0.20;
frmDevise = "EUR";
frmPaysDefaut = "France";
// ═══════════════════════════════════════════════════════
// UTILISATEUR
// ═══════════════════════════════════════════════════════
frmUtilisateurEmail = User().Email;
frmUtilisateurNom = User().FullName;
frmEstAdmin = frmUtilisateurEmail in ["admin@societe.fr", "superuser@societe.fr"];
// ═══════════════════════════════════════════════════════
// CALCULS MÉTIER
// ═══════════════════════════════════════════════════════
frmTotalHT = Sum(colPanier, Montant);
frmTotalTTC = frmTotalHT * (1 + frmTauxTVA);
// ═══════════════════════════════════════════════════════
// DONNÉES FILTRÉES
// ═══════════════════════════════════════════════════════
frmCommandesOuvertes = Filter(colCommandes, Statut <> "Fermé");
frmAlertes = Filter(colNotifications, NonLue = true);Éviter les formules trop complexes
// À éviter : formule monolithique difficile à maintenir
frmResultatComplexe = If(
And(
CountRows(Filter(colA, X > 10)) > 5,
Sum(Filter(colB, Y = "Active"), Z) > 1000
),
First(Sort(Filter(colC, ...), ...)).Valeur * 1.2,
Last(Sort(Filter(colD, ...), ...)).Valeur * 0.8
);
// Préférer : décomposition en formules intermédiaires
frmNombreElementsA = CountRows(Filter(colA, X > 10));
frmSommeElementsB = Sum(Filter(colB, Y = "Active"), Z);
frmConditionRemplie = frmNombreElementsA > 5 And frmSommeElementsB > 1000;
frmValeurCasVrai = First(Sort(Filter(colC, ...), ...)).Valeur * 1.2;
frmValeurCasFaux = Last(Sort(Filter(colD, ...), ...)).Valeur * 0.8;
frmResultatFinal = If(frmConditionRemplie, frmValeurCasVrai, frmValeurCasFaux);Exemple complet d’application
Contexte
Application de gestion de commandes avec calculs automatiques.
App.OnStart
ClearCollect(
colCommandes,
{ ID: 1, Client: "Dupont", Produit: "Laptop", Quantite: 2, PrixUnitaire: 899, Statut: "En cours" },
{ ID: 2, Client: "Martin", Produit: "Écran", Quantite: 3, PrixUnitaire: 349, Statut: "Livré" },
{ ID: 3, Client: "Bernard", Produit: "Clavier", Quantite: 5, PrixUnitaire: 79, Statut: "En cours" },
{ ID: 4, Client: "Petit", Produit: "Souris", Quantite: 10, PrixUnitaire: 29, Statut: "Annulé" }
)App.Formulas
// Configuration
frmTauxTVA = 0.20;
frmSeuilCommandeImportante = 1000;
// Statuts disponibles
frmStatuts = Table(
{ Code: "En cours", Couleur: RGBA(0,120,212,1), Icone: Icon.Clock },
{ Code: "Livré", Couleur: RGBA(16,124,16,1), Icone: Icon.CheckBadge },
{ Code: "Annulé", Couleur: RGBA(168,0,0,1), Icone: Icon.Cancel }
);
// Commandes enrichies avec calculs
frmCommandesAvecTotaux = AddColumns(
colCommandes,
"TotalHT", Quantite * PrixUnitaire,
"TotalTTC", Quantite * PrixUnitaire * (1 + frmTauxTVA),
"EstImportante", Quantite * PrixUnitaire >= frmSeuilCommandeImportante
);
// Filtres par statut
frmCommandesEnCours = Filter(frmCommandesAvecTotaux, Statut = "En cours");
frmCommandesLivrees = Filter(frmCommandesAvecTotaux, Statut = "Livré");
frmCommandesAnnulees = Filter(frmCommandesAvecTotaux, Statut = "Annulé");
// Statistiques globales
frmStatsGlobales = {
NombreTotal: CountRows(colCommandes),
NombreEnCours: CountRows(frmCommandesEnCours),
NombreLivrees: CountRows(frmCommandesLivrees),
NombreAnnulees: CountRows(frmCommandesAnnulees),
CATotal: Sum(frmCommandesAvecTotaux, TotalTTC),
CAEnCours: Sum(frmCommandesEnCours, TotalTTC),
CALivre: Sum(frmCommandesLivrees, TotalTTC),
PanierMoyen: Average(frmCommandesAvecTotaux, TotalTTC)
};
// Alertes
frmCommandesImportantesEnAttente = Filter(
frmCommandesEnCours,
EstImportante = true
);
frmNombreAlertes = CountRows(frmCommandesImportantesEnAttente);
frmAfficherBadgeAlerte = frmNombreAlertes > 0;Utilisation dans les contrôles
Galerie des commandes :
Items: frmCommandesAvecTotauxLibellé du total :
Text: "CA total : " & Text(frmStatsGlobales.CATotal, "#,##0.00 €")Badge d’alerte :
Visible: frmAfficherBadgeAlerte
Text: Text(frmNombreAlertes)Indicateur panier moyen :
Text: "Panier moyen : " & Text(frmStatsGlobales.PanierMoyen, "#,##0.00 €")Tableau récapitulatif
| Aspect | Détail |
| Emplacement | App.Formulas uniquement |
| Syntaxe | NomFormule = Expression; |
| Types retournés | Scalaire, table, enregistrement |
| Réactivité | Automatique (recalcule sur changement de dépendance) |
| Fonctions interdites | Collect, Set, Navigate, Patch, Remove, etc. |
| Références circulaires | Détectées et signalées comme erreur |
| Ordre de déclaration | Sans importance |
| Portée | Globale (toute l’application) |