Aller au contenu principal

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​

  1. Ouvrez l’écran dans le concepteur (Écrans → sélectionnez-en un → Concevoir).
  2. 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.
  3. Sous État de l’écran, appuyez sur Ajouter un champ d’état.
  4. 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.

Pourquoi l’état vit sur l’écran

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é​

  1. Sélectionnez n’importe quel objet sur le canevas.
  2. Dans l’onglet Écran, sous Liaisons, choisissez une propriété dans Lier une propriété.
  3. Un éditeur apparaît avec un exemple. Remplacez-le par votre expression.

Quatre propriétés peuvent être liées :

PropriétéPiloteSur
Textece qu’il dit — les mots d’un titre, le libellé d’un bouton, l’indication d’une zonetout
Affichés’il est présent à l’écrantout
Activési un contrôle peut être utilisécontrôles
Valeurce que contient un contrôlecontrô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​

  1. Sélectionnez le bouton.
  2. Sous Quand ceci se produit, choisissez Appuyé dans Gérer un événement.
  3. É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 :

AppelEffet
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.

Pour ne changer que l’apparence, dessinez un état

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.

Dites quelque chose ensuite

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.

Ce qu’un écran peut faire est décidé sur le serveur

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.

Pour envoyer quelqu’un vers une page, dessinez un lien

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.

Pas sur un portail

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 nomSignification
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 messageQue faire
Rien n’est sélectionné — ou plus d’un élément l’estSélectionnez exactement un objet
Le code s’écrit sur le composant lui-mêmeVous 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’écranIndiquez 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.

  1. 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.

  2. 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.

  3. Affichez-la depuis un gestionnaire, par le nom propre du composant :

    AppelOù elle apparaîtUtile pour
    showModal("Confirm card")centrée sur l’écran, avec un arrière-plan assombriune 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ébutdes filtres, un menu sur une fenêtre étroite
    openEndDrawer("Details card")sur toute la hauteur, depuis le bord de finun panneau de détails
  4. Fermez-la avec closeModal(), closeDropdown(), closeStartDrawer() ou closeEndDrawer() — 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") :

PositionOù 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​

NomContenu
statel’état propre de l’écran, de l’étape 1
screenscreen.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
uiui.theme (light ou dark), ui.locale (en, fa, ar) et ui.dir (ltr ou rtl) — les réglages propres au lecteur
userqui 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.paramsce 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 :

FonctionRenvoie
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 setState sur 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 showModal ne 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.