Rendre un écran réactif
Objectif
Faire faire quelque chose à un écran dessiné : un titre qui affiche le nom que quelqu’un a saisi, un panneau qui apparaît quand une case est cochée, un bouton Enregistrer qui ne s’active qu’une fois le formulaire rempli.
Rien de tout cela n’est une image, et rien de tout cela n’est du code que vous écrivez dans un fichier. C’est de l’état — la poignée de choses qui changent pendant que quelqu’un utilise l’écran — et des liaisons, des expressions d’une ligne qui le lisent.
Étape 1 — Donner un état à l’écran
- Ouvrez l’écran dans le concepteur (Écrans → sélectionnez-en un → Concevoir).
- Cliquez sur le cadre de l’écran lui-même — la boîte la plus extérieure — et ouvrez l’onglet Écran dans l’inspecteur à droite.
- Sous État de l’écran, appuyez sur Ajouter un champ d’état.
- Saisissez un nom — par exemple
requester— et une valeur de départ.
La valeur de départ est une expression, pas une valeur saisie : une zone vide commence donc à ""
(deux guillemets droits), une case à cocher à false et un compteur à 0. C’est le même langage que
tout le reste de cet écran, c’est pourquoi il n’y a qu’une chose à apprendre.
Ajoutez-en autant que l’écran en a besoin. La plupart des écrans en ont besoin de deux ou trois.
Parce que deux contrôles lisent le même champ. Si l’état appartenait à la boîte depuis laquelle vous l’avez ajouté, supprimer cette boîte emporterait le champ avec elle — et tout ce qui le lit cesserait discrètement de fonctionner.
Étape 2 — Lier une propriété
- Sélectionnez n’importe quel objet sur le canevas.
- Dans l’onglet Écran, sous Liaisons, choisissez une propriété dans Lier une propriété.
- Un éditeur apparaît avec un exemple. Remplacez-le par votre expression.
Quatre propriétés peuvent être liées :
| Propriété | Pilote | Sur |
|---|---|---|
| Texte | ce qu’il dit — les mots d’un titre, le libellé d’un bouton, l’indication d’une zone | tout |
| Affiché | s’il est présent à l’écran | tout |
| Activé | si un contrôle peut être utilisé | contrôles |
| Valeur | ce que contient un contrôle | contrôles |
Tout le reste d’un objet — sa position, sa taille, sa couleur — vous l’avez dessiné, et le dessin est la meilleure façon de dire tout cela.
Des exemples qui font un vrai travail :
state.requester the Text of a heading
"Hello, " + state.requester the same, with words around it
state.showDetails the Shown of a panel
!state.showDetails the Shown of the line that says it is empty
state.requester != "" the Enabled of a Save button
screen.width > 700 the Shown of something a narrow window has no room for
L’éditeur est l’éditeur BS Lang de la plateforme : il souligne ce qu’il ne comprend pas et propose des complétions pendant que vous tapez. Si le soulignement est là, survolez-le pour savoir pourquoi.
Étape 3 — Laisser un contrôle réécrire
Liez la Valeur d’une zone de texte à state.requester, et taper dedans définit
state.requester. Tout ce qui lit ce champ suit immédiatement — la salutation, le bouton
Enregistrer, tout.
C’est tout ce qui donne vie à un écran, et cela ne demande aucun gestionnaire.
Une règle : la réécriture n’a lieu que lorsque la Valeur est un simple chemin d’état —
state.requester, ou state.form.name. Si elle est calculée (state.first + " " + state.last), le
contrôle affiche la valeur et est en lecture seule, car il n’y a aucun moyen de remonter de ce
que quelqu’un a tapé aux deux champs dont cela provient.
Étape 4 — Déclencher une action quand on appuie sur un bouton
- Sélectionnez le bouton.
- Sous Quand ceci se produit, choisissez Appuyé dans Gérer un événement.
- Écrivez ce qui doit se passer — une instruction par ligne :
notify("Ticket raised for " + getState("requester"));
setState("requester", "");
setState("showDetails", false);
Ce qu’un gestionnaire peut appeler :
| Appel | Effet |
|---|---|
setState("name", value) | modifie l’état de l’écran — tout ce qui le lit suit |
getState("name") | le relit, pour calculer à partir de ce qui s’y trouve |
loadRecords("table", "field") | charge des lignes d’une table dans un champ d ’état — voir plus bas |
getRecord("table", id, "field") | charge un enregistrement par son identifiant |
createRecord("table", { … }, "field") | stocke un nouvel enregistrement ; le troisième argument est facultatif |
updateRecord("table", id, { … }) | modifie les champs que vous nommez sur un enregistrement |
deleteRecord("table", id) | supprime un enregistrement |
callApi("GET", "psl/v1/overview", { … }, "field") | interroge une Custom API et garde sa réponse — voir Des chiffres venant d’une Custom API |
notify("…") / notifyError("…") | informe la personne qui utilise l’écran |
showModal("Card") / closeModal() | affiche une carte superposée sur l’écran — voir l’étape 5 |
openStartDrawer("Card") / closeStartDrawer() | en fait glisser une depuis le bord de début |
openEndDrawer("Card") / closeEndDrawer() | et depuis le bord de fin |
openDropdown("Card") / closeDropdown() | en ouvre une à côté de ce sur quoi on a appuyé |
setVisualState("name") | place dans cet état l’objet le plus proche au-dessus de ce gestionnaire qui possède un état dessiné ; "" revient à Normal — voir Réutiliser un design avec des composants |
openUrl("…", "newTab") | ouvre une adresse web ; omettez le second argument pour rester dans cette fenêtre |
navigate("Screen") | va vers un autre écran de cette application — par le nom inscrit sur son cadre |
reloadSurfaces() | réaffiche chaque table ou formulaire intégré à cet écran, avec des données fraîches |
Un gestionnaire est un petit programme, pas une expression. Il peut modifier des choses — c’est toute sa raison d’être — et il peut compter autant de lignes que nécessaire. C’est la différence avec une liaison, qui ne fait que lire.
Les autres événements sont là quand vous en avez besoin : Appuyé deux fois, Valeur modifiée (sur un contrôle), Prend le focus, Perd le focus, Arrivée du pointeur, Départ du pointeur, et — sur le cadre de l’écran lui-même — Ouverture de l’écran, qui s’exécute une fois, après que l’état existe.
Un gestionnaire qui se contente de recolorer quelque chose coûte du travail à chaque mouvement du pointeur. Un état dessiné ne coûte rien du tout, car c’est le navigateur qui s’en charge. Voir Réutiliser un design avec des composants.
Aller vers un autre écran de l’application
Une application contient plusieurs écrans, et navigate permet de passer de l’un à l’autre :
navigate("Details");
navigate("Details", { id: getState("chosen") });
Le nom est celui inscrit sur le cadre de l’écran, exactement tel que vous l’y avez saisi —
renommez le cadre et chaque navigate qui nomme l’ancien nom cesse de fonctionner, ce que l’écran
vous signale au moment de l’appui plutôt que d’échouer en silence.
Ce qui survit au déplacement, et ce qui ne survit pas. L’écran que vous quittez est fermé : son
état disparaît, si bien qu’en y revenant vous en obtenez un neuf — un formulaire à moitié rempli ne
devrait pas l’être encore, et un écran qui chargeait des lignes à l’arrivée les charge de nouveau. Ce
qui voyage, c’est ce que vous transmettez : le second argument arrive sous la forme de
screen.params, si bien que screen.params.id sur l’écran suivant lit ce que vous avez envoyé.
C’est toujours screen.params. Il n’existe pas de params plus court, et l’éditeur de code le souligne.
La barre d’adresse vous suit. Chaque écran a sa propre URL : le bouton Précédent du navigateur
revient à l’écran d’avant, une actualisation ramène au même, et un lien que vous copiez s’ouvre à cet
endroit. Les valeurs transmises ne voyagent pas ainsi — arriver par Précédent, par une
actualisation ou par un lien collé ouvre l’écran sans screen.params — considérez-les donc comme un
passage de relais entre deux écrans plutôt que comme quelque chose qu’un lien peut transporter.
Lire et écrire des enregistrements
Cinq appels qui, à eux tous, transforment un dessin en application.
Lire une liste :
loadRecords("par_ticket", "tickets");
loadRecords("par_ticket", "tickets", 20);
loadRecords("par_ticket", "tickets", { top: 20, where: { par_status: "Open" }, orderBy: "par_name" });
Les lignes arrivent dans le champ d’état que vous avez nommé, et tout le reste de l’écran sait déjà
quoi en faire — un tableau se répète sur state.tickets, une légende lit
state.tickets.length(). Voir
Dessiner une ligne, en obtenir une par enregistrement.
Le troisième argument est soit le nombre maximal, soit la question complète : top, where,
orderBy et descending. where ne compare que l’égalité, et chaque paire que vous écrivez doit
correspondre. Quand il vous en faut plus — une plage, « contient », un ou — construisez une
vue avec le concepteur de requêtes et dessinez l’écran à partir d’elle plutôt que de tout
comprimer ici en une ligne.
En lire un :
getRecord("par_ticket", screen.params.id, "ticket");
C’est le pendant de navigate("Details", { id: row.id }) — l’écran de liste transmet l’identifiant,
et l’écran de détails récupère l’enregistrement correspondant. S’il n’existe plus, le champ est
laissé tel quel plutôt que vidé, pour que les liaisons qui en dépendent continuent de fonctionner.
Écrire :
createRecord("par_ticket", { par_name: getState("title"), par_status: "Open" });
createRecord("par_ticket", { par_name: getState("title") }, "created");
updateRecord("par_ticket", getState("ticket").id, { par_status: "Closed" });
deleteRecord("par_ticket", getState("ticket").id);
Le troisième argument de createRecord est facultatif, et il vaut souvent la peine de
l’écrire : la plateforme répond avec l’enregistrement stocké, identifiant compris, si bien que
getState("created").id est la façon dont l’écran ouvre ou met à jour ensuite ce qu’il vient de
créer. Sans lui, il n’y a aucun moyen de connaître cet identifiant.
Les noms de champ sont les noms logiques des colonnes de la table — par_name, pas Nom — ceux
qu’affiche le concepteur de tables.
Rien n’indique à la personne qui utilise l’écran qu’une écriture a réussi : dites-le vous-même,
createRecord(…); notify("Ticket raised");. Si la plateforme refuse l’écriture — un champ
obligatoire, une autorisation — l’écran affiche la raison qu’elle a donnée, c’est pourquoi le message
vaut la peine d’être lu plutôt que remplacé.
Le reste de ce clic s’arrête alors, si bien qu’un notify ou un navigate après l’écriture n’a lieu que si elle a réussi.
Chacun de ces appels est vérifié par rapport aux autorisations de la personne qui utilise l’application, à chaque appel. Masquer un bouton Supprimer masque un bouton ; cela n’empêche rien.
openUrl sert quand l’écran décide où aller — après un enregistrement, ou selon ce qui a été
choisi. Quand la destination est simplement connue, dessinez plutôt un lien : le clic du milieu,
le clic droit → Ouvrir dans un nouvel onglet et la liste des liens d’un lecteur d’écran
fonctionnent tous sur un vrai lien, et sur rien d’autre. Voir
Dessiner une application Studio.
Des chiffres venant d’une Custom API
Un chiffre — les réservations du jour, le chiffre d’affaires du mois — est une période et une
somme, souvent sur plusieurs tables, ce que loadRecords ne sait pas demander. Calculez-le dans une
Custom API et appelez-la depuis l’écran :
callApi("GET", "psl/v1/overview", { date: "2026-10-06" }, "figures");
L’adresse est celle de l’API elle-même sous l’environnement : son préfixe d’éditeur, sa version
et sa route. Avec GET, les entrées partent en chaîne de requête ; avec POST et les autres, en
corps. La réponse arrive dans le champ d’état indiqué, si bien qu’un texte lié à
state.figures.bookingsToday l’affiche. L’API s’exécute avec les droits de la personne qui utilise
l’écran.
Une page de portail lit les tables que son portail liste et ne nomme jamais d’API ; callApi y
affiche un message au lieu d’une réponse.
Quand la zone est trop petite : la page de code
Une liaison tient sur une ligne et a sa place à côté de ce qu’elle pilote. Un gestionnaire
grossit — et après le troisième if, le petit éditeur du panneau devient une fente de boîte aux
lettres.
Sélectionnez d’abord l’objet, puis appuyez sur Écrire du code dans la barre d’outils (le
bouton </>). Le concepteur est recouvert — la page qui l’entoure reste — par une liste de tout ce
qui est scriptable sur cet objet, sur le côté, et un éditeur avec de la place pour écrire. La liste
contient ses liaisons, ses gestionnaires, les champs d’état de l’écran et les propriétés propres d’un
composant. Ceux qui ne sont pas encore écrits sont aussi listés, ce qui est la réponse la plus rapide
à « que pourrais-je mettre là-dessus ? ».
La liste indique lesquels sont écrits, pour que vous n’ayez jamais à en ouvrir un pour le savoir :
| À côté du nom | Signification |
|---|---|
| Un point vert, nom en gras | Écrit, et cohérent |
| Un point rouge, nom en gras | Écrit, mais contient une erreur — ouvrez-le et l’éditeur souligne où |
| Un point creux, nom estompé | Rien d’écrit pour l’instant |
Tant que la page de code est affichée, le clavier appartient à l’éditeur. Taper t tape un t ;
cela n’active pas l’outil Texte derrière la page.
Pour revenir, appuyez sur Concevoir — le même bouton que celui qui vous ramène d’un aperçu, au même endroit en haut de la page. Le dessin est exactement tel que vous l’avez laissé : même sélection, même zoom. Et c’est le même document dans les deux cas : un gestionnaire écrit ici apparaît dans le panneau là-bas.
S ’il ne se passe rien quand vous appuyez dessus, un message explique pourquoi, et il n’y a que trois raisons :
| Le message | Que faire |
|---|---|
| Rien n’est sélectionné — ou plus d’un élément l’est | Sélectionnez exactement un objet |
| Le code s’écrit sur le composant lui-même | Vous avez sélectionné une copie (une instance) ou une variante. Clic droit → Aller au composant principal et écrivez-le là — chaque copie en bénéficie |
| Cet objet fait partie du graphisme de l’écran | Indiquez d’abord ce qu’il est dans l’onglet Écran — un bouton, une zone de texte — et il aura alors des gestionnaires à écrire |
Un composant s’écrit sur sa copie principale. Sélectionnez le cadre dont le composant est fait — pas une copie de celui-ci sur un écran — et la liste propose Appuyé et le reste, exactement comme pour n’importe quoi d’autre. C’est là qu’est la place du comportement d’un composant : écrivez-le une fois, et chaque copie sur chaque écran l’applique.
Étape 5 — Demander avant d’agir, dans une fenêtre modale, un menu déroulant ou un tiroir
Une carte superposée est un morceau d’écran qui n’est pas là tant qu’un gestionnaire ne l’affiche pas.
-
Dessinez son contenu une fois, sous forme de composant. Une carte avec une question et deux boutons est un composant comme un autre — voir Réutiliser un design avec des composants — si bien que la même confirmation peut servir sur chaque écran qui en a besoin. Dessinez-la à côté de votre écran, là où il y a de la place.
-
Sélectionnez le composant et cochez Une carte superposée dans l’onglet Graphique. C’est toute la configuration : il cesse d’être dessiné sur l’écran et devient quelque chose qu’un gestionnaire peut afficher.
-
Affichez-la depuis un gestionnaire, par le nom propre du composant :
Appel Où elle apparaît Utile pour showModal("Confirm card")centrée sur l’écran, avec un arrière-plan assombri une question à laquelle il faut répondre avant toute autre chose openDropdown("Menu card")attachée à ce sur quoi on a appuyé un petit menu, une indication, un court formulaire openStartDrawer("Filters card")sur toute la hauteur, glissant depuis le bord de début des filtres, un menu sur une fenêtre étroite openEndDrawer("Details card")sur toute la hauteur, depuis le bord de fin un panneau de détails -
Fermez-la avec
closeModal(),closeDropdown(),closeStartDrawer()oucloseEndDrawer()— depuis un bouton à l’intérieur, par exemple. Un tiroir n’a pas de bouton de fermeture propre : dessinez-en un dans la carte, comme le font les menus des exemples. Échap et un clic à côté du tiroir le ferment quand même.
Une carte à laquelle il faut répondre
Sous la case Une carte superposée, il y en a une seconde : Une réponse est obligatoire. Lorsqu’elle est cochée, cliquer hors de la carte, appuyer sur Échap et le bouton de fermeture cessent tous de fonctionner tant qu’elle est ouverte — et le bouton de fermeture n’est pas affiché du tout, car un contrôle visiblement présent qui ne fait rien ressemble à une page figée pour qui appuie deux fois dessus.
Laissez-la décochée sauf si la carte pose une question à laquelle on ne peut pas répondre en s’en allant. Une superposition ouverte par accident doit se fermer comme elle s’est ouverte ; le seul type qui ne doit pas le faire est celui qui existe pour obtenir une réponse — « supprimer ces quatre enregistrements ? », « cet enregistrement a été modifié par quelqu’un d’autre, lequel garder ? » — où cliquer sur l’arrière-plan n’est pas une réponse et se lit pourtant comme telle.
Dessinez votre propre sortie. Une carte obligatoire refuse tous les moyens de fermeture que
fournit la plateforme : elle a donc besoin de son propre bouton exécutant closeModal(),
closeStartDrawer() ou closeEndDrawer(). Placez-le en premier et sans mise en valeur, comme un
Annuler à côté d’un Supprimer.
Un menu déroulant l’ignore. Un menu qui ne se ferme pas en cliquant ailleurs piège la page, et un menu déroulant n’est jamais la façon de poser une question.
Un menu déroulant s’ouvre contre ce qui a exécuté le gestionnaire. Il n’y a rien à choisir :
placez openDropdown("Menu card") sur le bouton, et le menu apparaît à côté de ce bouton.
Vous pouvez préciser où — openDropdown("Menu card", "bottom-end") :
| Position | Où va la carte |
|---|---|
"bottom" (par défaut) | sous le bouton, centrée sur lui |
"bottom-start" / "bottom-end" | en dessous, alignée sur son bord de début / de fin |
"top", "top-start", "top-end" | au-dessus — pour un contrôle proche du bas d’un écran |
end, pas right. Une carte ouverte en bottom-end pend du bord droit du bouton en anglais et
de son bord gauche en persan et en arabe, ce qui est la même règle que suivent les tiroirs : un seul
script place le menu du bon côté dans chaque langue. Écrire "bottom-right" donnerait un écran
inversé en persan sans que rien ne le signale — ce n’est donc pas une position, et un gestionnaire
qui en demande une est averti.
Vous exprimez une préférence, pas une promesse : s’il n’y a pas de place en dessous, le menu s’ouvre quand même au-dessus. Un menu qui déborde de l’écran est pire qu’un menu de l’autre côté.
Sa largeur est celle que vous avez dessinée. La largeur propre de la carte est celle du tiroir et celle de la fenêtre modale — donnez donc à la carte la taille que vous voulez pour le panneau.
Il y en a une de chaque, et afficher une seconde carte remplace la première. Un écran ne peut avoir qu’une fenêtre modale ouverte à la fois, c’est pourquoi il n’y a rien à déclarer : les hôtes sont toujours là, et votre gestionnaire dit ce qui va dedans.
Le bord d’un tiroir suit la langue, pas le dessin. Le début est la gauche pour quelqu’un qui lit l’anglais et la droite pour quelqu’un qui lit le persan ou l’arabe — tout l’écran se reflète, car dans une application, ce que vous avez dessiné est l’habillage.
Échap, l’arrière-plan et un clic à l’extérieur ferment tous une superposition, et le focus revient à ce qui l’a ouverte. Rien de tout cela n’est à régler.
Étape 6 — Prévisualiser
Appuyez sur Aperçu. L’aperçu est le véritable moteur d’exécution — le même composant que celui que monte le Shell, pas une approximation — ce que vous voyez est donc ce que voit la personne qui utilise l’application.
Tapez dans les zones. Regardez le reste de l’écran suivre.
Règles à connaître
Une liaison ne fait que lire. Elle se réexécute chaque fois que ce qu’elle lit change : une liaison qui modifierait quelque chose ne cesserait donc de se relancer. Le concepteur en refuse une à l’enregistrement et vous indique quel objet et quelle propriété — tout ce qui modifie quelque chose a sa place dans un gestionnaire.
« Affiché » retire, il ne masque pas. Un élément dont Affiché est faux n’est pas du tout sur la page : la touche Tab ne l’atteint pas, aucun lecteur d’écran ne l’annonce, et Ctrl+F ne le trouve pas. C’est presque toujours ce que vous vouliez.
Rien ici ne relève de la sécurité. Un bouton masqué est un bouton masqué. Ce qu’une personne peut réellement faire est décidé sur le serveur, à chaque fois, quoi qu’affiche l’écran.
Ce qu’une liaison peut voir, aujourd’hui
| Nom | Contenu |
|---|---|
state | l’état propre de l’écran, de l’étape 1 |
screen | screen.width et screen.height — la surface, pour qu’un écran puisse réagir à une fenêtre étroite — et screen.name, l’écran sur lequel vous êtes, pour qu’une barre placée sur chaque écran puisse signaler sa propre page |
ui | ui.theme (light ou dark), ui.locale (en, fa, ar) et ui.dir (ltr ou rtl) — les réglages propres au lecteur |
user | qui est connecté : user.name, user.email et user.photo (vide s’il n’a pas de photo ; liez donc le Shown d’une image à user.photo != "") — de quoi faire un accueil ou une barre du haut, et volontairement pas ses rôles |
screen.params | ce qu’a transmis l’écran qui vous a envoyé ici — navigate("Details", { id }) |
Les enregistrements y arrivent par un gestionnaire, pas par un nom qui leur serait propre.
loadRecords et getRecord les placent dans l’état propre de l’écran, si bien qu’une liaison lit
state.tickets comme n’importe quoi d’autre — il n’y a pas de second endroit où chercher. Ce qui
manque vraiment encore, ce sont les vues enregistrées de la plateforme : un écran nomme une table
et un where, pas une vue.
Ce qu’une liaison peut calculer
Une liaison est une expression : elle ne peut ni boucler ni appeler setState. Quelques petites
fonctions couvrent ce dont une légende a généralement besoin au-delà de l’arithmétique :
| Fonction | Renvoie |
|---|---|
text(value) | la valeur sous forme de mots, pour qu’un nombre puisse s’insérer dans une phrase — "of " + text(state.total) |
num(value) | les mots sous forme de nombre — ce que renvoie une liste déroulante, prêt pour l’arithmétique ; 0 si ce n’en est pas un |
first(list, { field: value, … }) | la première ligne d’une liste chargée dont les champs contiennent ces valeurs, ou null — first(state.budgets, { par_department: state.department, par_category: state.category }) |
format(value, "integer" | "number" | "percent") | un nombre tel que l’écrit votre langue — format(174500, "integer") donne 174,500 en anglais et des chiffres persans en persan |
translate({ en: "…", fa: "…", ar: "…" }) | les mots dans la langue du lecteur, avec repli sur l’anglais — voir Deux langues |
first est la façon dont une légende suit un sélecteur jusqu’à la ligne qu’il désigne. Chargez
la table une fois, à l’ouverture de l’écran ; ensuite,
"Available: £" + format(first(state.budgets, { … }).par_remainingbudget, "integer") suit deux
listes déroulantes où qu’elles aillent, sans gestionnaire. Une ligne chargée porte une colonne de
choix sous forme de libellé, et une liste déroulante renvoie le libellé qu’elle proposait : les
deux concordent donc. Couvrez le cas où rien ne correspond avec une condition —
first(…) == null ? "Choose a line" : … — car lire un champ sur null fait échouer la liaison, et
&& ne protège pas : les deux côtés d’un && sont toujours évalués.
Une plage relève d’un gestionnaire. first compare des valeurs exactes ; « la tranche dont le
minimum et le maximum encadrent ce montant » est une boucle, et une boucle a sa place dans le
gestionnaire Valeur modifiée du contrôle, qui écrit ce qu’il a trouvé dans l’état pour que la
légende le lise. L’exemple studio-capital-planning dans samples/solutions fait les deux sur un
même écran.
Deux langues sur un même écran
Liez le Texte d’un texte à translate(...), avec chaque langue à côté de l’anglais :
translate({ en: "Opening times", fa: "ساعات کار" })
et donnez à la page un bouton qui bascule : if (ui.locale == "fa") { setLanguage("en"); } else { setLanguage("fa"); }.
setLanguage change la langue de la plateforme, pas seulement celle de l’écran : elle est
mémorisée, et en persan ou en arabe, toute la page se reflète, car chaque position que dessine un
écran s’exprime en début et fin plutôt qu’en gauche et droite. ui.dir indique le sens de lecture,
pour qu’une flèche puisse pointer dans la bonne direction.
Une langue que l’objet ne possède pas se replie sur l’anglais : une page à moitié traduite se lit donc en anglais plutôt que sous forme de blancs. L’exemple portal-pages-and-navigation est écrit ainsi, jusqu’au dernier mot.
Quelque chose qui se produit tout seul : le minuteur
Donnez à un objet un gestionnaire Tic du minuteur et liez son Intervalle du minuteur (ms) — il exécute ce gestionnaire toutes les tant de millisecondes tant que l’objet est sur la page :
Timer interval (ms): state.held ? 0 : 5000
Timer ticks: setState("slide", (getState("slide") + 1) % 3);
Zéro, ou rien, signifie arrêté — la pause fait donc partie de la liaison, et un carrousel qui
s’interrompt quand vous le pointez règle held dans ses gestionnaires Arrivée du pointeur et
Départ du pointeur. En dessous de 250, la valeur est relevée à 250. Un objet masqué ne se déclenche
pas. Le carrousel de la bibliothèque de composants, et celui de la page d’accueil de
portal-pages-and-navigation, sont construits ainsi.
Dépannage
- « Une liaison sur … n’a pas pu s’exécuter » — l’expression est valide, mais quelque chose qu’elle nomme est absent. La cause la plus courante est un champ d’état orthographié différemment de la liaison : vérifiez la liste État de l’écran du cadre de l’écran.
- La zone ne me laisse pas taper. — sa Valeur est une expression calculée, elle est donc en lecture seule par conception. Liez-la plutôt à un simple champ d’état, et calculez l’autre chose ailleurs.
- Rien ne se passe quand je tape. — la zone n’a pas de liaison Valeur. Une zone sans liaison garde ce qui est tapé et ne le dit à personne.
- Le bouton Enregistrer ne s’active jamais. — vérifiez son expression Activé face à une
valeur vide :
state.requester != ""n’est vrai qu’une fois quelque chose tapé. - Appuyer sur le bouton ne fait rien. — un contrôle désactivé ne reçoit aucun appui : vérifiez d’abord sa liaison Activé ; vérifiez ensuite que le gestionnaire est sur Appuyé et non sur un événement qui ne se déclenche jamais ici (Ouverture de l’écran appartient au cadre de l’écran, Valeur modifiée à un contrôle).
- « Un gestionnaire sur … n’a pas pu s’exécuter » — le gestionnaire est du BS Lang valide, mais
quelque chose qu’il nomme est absent. La cause la plus courante est un
setStatesur un champ que l’écran n’a jamais déclaré. - « createRecord("…") a échoué : … » — la plateforme a refusé l’écriture, et ce qui suit les deux-points est sa propre raison : un champ obligatoire vide, une valeur qui ne fait pas partie des choix, ou une autorisation que vous n’avez pas. Vérifiez d’abord les noms de champ dans le concepteur de tables — un nom logique mal orthographié est la cause la plus courante.
- Rien ne se charge, et rien ne se plaint. — vous êtes dans l’Aperçu, qui n’a aucun environnement derrière lui. Les appels d’enregistrement n’y font rien, à dessein. Ouvrez l’application depuis le Shell pour voir de vrais enregistrements.
showModal("…")ne fait rien. — le nom doit correspondre exactement à celui du composant, et Une carte superposée doit être cochée sur le composant. Une carte supprimée ou renommée laisse des gestionnaires qui la nomment, et ceux-ci ne font discrètement rien plutôt que de casser l’écran.- La carte s’affiche sur l’écran au lieu de dans une fenêtre modale. — Une carte superposée n’est pas cochée. Tant qu’elle ne l’est pas, le composant est dessiné là où vous l’avez placé, comme n’importe quel autre composant.
- « Deux composants s’appellent tous deux … » — une carte s’affiche par le nom de son composant :
deux composants partageant un nom posent une question à laquelle
showModalne peut pas répondre. Renommez-en un.
Essayez
Importez l’exemple de solution Ticket Triage. C’est cette page, construite : trois champs d’état, des propriétés liées partout, un état que l’exemple a lui-même nommé, une fenêtre modale qui demande confirmation avant de créer le ticket, et une fenêtre contextuelle qui s’ouvre depuis son propre bouton.