Calculs et dépendances
Chaque CalculatedField possède une expression calculate. Les calculs sont la première étape de
chaque passe d'évaluation : les conditions et la validation
voient donc toujours des valeurs calculées à jour. Cette page explique dans quel ordre les calculs
s'exécutent et ce qui se passe quand une expression ne peut pas produire de valeur.
Référencer des champs
Dans une expression, $data_name lit la valeur actuelle d'un champ. Les expressions référencent les
champs par leur data_name, tandis que les conditions utilisent field_id.
Les valeurs gardent la forme sous laquelle le moteur les stocke. Un NumericField fournit un nombre,
mais un champ à choix fournit un objet contenant les choix sélectionnés. Utilisez des builtins comme
CHOICEVALUE et
CHOICELABEL pour lire les champs à choix.
Une expression est du JavaScript. Pour une logique qui ne tient pas sur une ligne, écrivez du code
sur plusieurs lignes et renvoyez le résultat avec
SETRESULT.
Ordre des dépendances
À la création d'un moteur, celui-ci lit une fois chaque expression calculate et note les
$fields qu'elle référence. Pendant l'évaluation, un champ calculé s'exécute toujours après les
champs calculés dont il dépend. L'ordre des champs dans le schéma n'a pas d'importance.
Par exemple, ces champs sont déclarés dans l'ordre inverse :
| Champ (ordre dans le schéma) | calculate |
|---|---|
total | $subtotal + $tax |
tax | $subtotal * 0.2 |
subtotal | $qty * $price |
Avec qty à 2 et price à 10, le moteur exécute d'abord subtotal (20), puis tax (4), puis
total (24). Une seule passe suffit, quelle que soit la longueur de la chaîne.
Cycles
Un cycle apparaît quand des champs calculés dépendent les uns des autres en boucle, soit directement
(a utilise $a), soit par d'autres champs (a utilise $b et b utilise $a). Le moteur ne
peut pas ordonner ces champs, donc il :
- met à
nullchaque champ du cycle ; - émet, via
WarningSystem, un diagnostic de dépendance qui nomme le cycle, par exempleCalculatedField dependency cycle detected: a -> b; et - calcule quand même tous les autres champs.
Le diagnostic de cycle n'est pas ajouté à la table errors de validation des valeurs dans l'état du
formulaire.
Un champ qui référence un champ du cycle s'exécute quand même, avec null en entrée. En JavaScript,
null * 2 vaut 0, donc c avec $a * 2 affiche 0 et non null.
Un cycle ne rend pas le schéma invalide : la création du moteur réussit. Le diagnostic apparaît lors de l'évaluation du formulaire. Pour le corriger, cassez la boucle, par exemple en transformant l'un des champs en champ de saisie.
Quand une expression échoue
Si une expression lève une erreur, par exemple parce qu'elle appelle une méthode sur null, ce champ
calculé est mis à null pour cette passe. Les autres champs calculés s'exécutent quand même ; un
champ qui dépend du champ en échec reçoit null et peut produire une autre valeur ou échouer à son
tour.
Si une expression référence un champ qui n'existe pas dans le schéma, le moteur signale aussi un
avertissement qui nomme ce champ. Dans le mode de sécurité SAFE, une
expression qui utilise quelque chose que le mode n'autorise pas est rejetée et le champ est mis à
null.
Références dynamiques avec EVAL()
EVAL lit un champ dont le nom est fourni sous
forme de chaîne. La façon dont le moteur l'ordonne dépend de cette chaîne :
- Un nom fixe, comme
EVAL('$price'), est traité comme$priceet ordonné normalement. - Un nom construit à l'exécution, comme
EVAL('$' + $unit + '_price'), ne peut pas être connu à l'avance.
Dès qu'un champ calculé utilise un nom construit à l'exécution, le moteur ne peut plus garantir l'ordre. Il exécute alors tous les champs calculés de façon répétée jusqu'à ce qu'aucune valeur ne change, avec au plus une passe par champ calculé (au moins deux). Si des valeurs changent encore après la dernière passe, il signale un avertissement qui nomme ces champs. Il signale aussi un avertissement pour chaque champ qui utilise un nom construit à l'exécution.
Préférez les références directes
Écrivez $price plutôt que EVAL('$price') chaque fois que le nom du champ est connu. Les
références directes conservent une seule passe ordonnée et rendent les dépendances visibles pour
toute personne qui lit le schéma.
Voir les erreurs et les avertissements
Le moteur signale comme avertissements les cycles, les noms construits à l'exécution dans EVAL(),
les valeurs qui ne se stabilisent pas et les références à des champs inexistants. En développement,
il les affiche dans la console. Node.js est considéré en développement sauf si NODE_ENV vaut
production. Dans un navigateur, les pages sur localhost, 127.0.0.1 ou une URL avec un port
explicite sont considérées en développement.
Pour collecter ces avertissements dans votre application, passez votre propre WarningSystem :
Code
Vous pouvez aussi enregistrer un callback avec warningSystem.addWarningHandler(handler). Le même
avertissement répété en moins d'une seconde n'est signalé qu'une fois.
Une expression qui lève une erreur n'est pas un avertissement. Le moteur l'affiche dans la console
sous la forme [form0] Expression evaluation failed, dans tous les environnements, et met le champ
à null.
Champs calculés dans les sections répétables
Un champ calculé placé dans une RepeatableSection s'exécute une fois par ligne. Il peut référencer
les champs du formulaire principal, les champs de sa propre ligne et les champs des lignes qui la
contiennent. Une référence à un champ hors de cette portée lit undefined et produit un
avertissement. Voir Portées parent et enfant.