Ihre erste Studio-App bauen
Ziel
Eine funktionierende Anwendung aus dem Nichts bauen: eine Tabelle für die Datensätze, ein Bildschirm, der sie zeigt, eine Symbolleiste, die auf den angehakten wirkt, und ein Seitenbereich, der einen neuen Datensatz zurückschreibt.
Beim ersten Mal dauert es etwa vierzig Minuten. Nichts davon ist Spielerei – jeder Schritt ist der Schritt, den Sie für eine echte App gehen würden, und am Ende haben Sie ungefähr das Beispiel Support desk.
studio-starter-app in samples/solutions ist genau diese App, gezeichnet. Importieren Sie sie über
Lösungen → Importieren, öffnen Sie sie, und drücken Sie auf Dinge. Wenn Sie danach hierher
zurückkehren, wird jeder Schritt unten kürzer.
Bevor Sie beginnen
- Sie sind als Ersteller angemeldet.
- Eine Umgebung und eine Lösung sind in den Auswahlfeldern oben auf der Seite ausgewählt. Nichts, was Sie unten erstellen, existiert außerhalb davon.
- Sie kennen das Herausgeberpräfix Ihrer Lösung – die zwei oder drei Buchstaben vor jedem
logischen Namen. Diese Seite schreibt
par; Ihres kann abweichen.
1. Eine Tabelle für die Datensätze
Eine App, die nichts zeigt, ist eine Zeichnung. Erstellen Sie zuerst die Tabelle.
Tabellen → Neu, und füllen Sie aus:
| Feld | Wert |
|---|---|
| Anzeigename | Case |
| Pluralname | Cases |
| Logischer Name | par_case (das Präfix wird für Sie ergänzt) |
| Primärfeld | Summary |
Speichern Sie, und fügen Sie dann auf der Registerkarte Felder drei weitere Felder hinzu:
| Anzeigename | Logischer Name | Typ |
|---|---|---|
| Priority | par_priority | Auswahl – neuer Optionssatz par_case_priority, Optionen Low, Normal, High |
| Urgent | par_urgent | Ja/Nein |
| Notes | par_notes | Mehrzeiliger Text |
Ein Datensatz, der erstellt wurde, ohne Urgent anzurühren, hat dafür überhaupt keinen Wert – und
kein Wert ist kein boolescher Wert. Ein Ausdruck wie record.par_urgent ? "Yes" : "No" schlägt daher
genau bei diesen Datensätzen mit Only booleans are allowed in this expression fehl. Schreiben Sie
(record.par_urgent ?? false), wo immer Sie ein optionales Feld lesen, und die Frage erledigt sich.
Das ist die häufigste Überraschung in einer ersten App.
2. Die App
Studio-Apps → Neu:
| Feld | Wert |
|---|---|
| Anzeigename | Support desk |
| Logischer Name | par_support |
| Beschreibung | Ein Satz. Ihn zeigt die Kachel im App-Starter unter dem Namen. |
| Symbol | Drücken Sie auf die Auswahl, und wählen Sie eines – LifeBuoy passt zu einer Support-App |
| In der Shell aufgeführt | an |
Drücken Sie Speichern, dann Entwerfen. Die Zeichenfläche öffnet sich.
3. Der Bildschirm, und was ein Bildschirm ist
Zeichnen Sie einen Rahmen, der die Zeichenfläche füllt – etwa 1200 × 760 ist eine angenehme Zeichengröße –, und öffnen Sie bei ausgewähltem Rahmen die Registerkarte Bildschirm im Inspektor rechts:
┌─ Inspector ───────────────────────┐
│ Graphic │ Screen │ Code │
├───────────────────────────────────┤
│ This object is … │
│ ┌─────────────────────────────┐ │
│ │ The screen ▾ │ │ ← choose this
│ └─────────────────────────────┘ │
│ │
│ Content that does not fit │
│ ┌─────────────────────────────┐ │
│ │ Show it — it spills out ▾ │ │
│ └─────────────────────────────┘ │
└───────────────────────────────────┘
Benennen Sie den Rahmen Cases im Bereich Ebenen um. Dieser Name ist der Name des Bildschirms –
danach fragt später navigate("Cases").
Die gezeichnete Größe ist nicht die endgültige Größe. Alles darin ist an den Kanten des Rahmens angeheftet, und der Rahmen füllt jedes Fenster, in dem die App geöffnet wird.
4. Das eigene Gedächtnis des Bildschirms
Ein Bildschirm merkt sich Dinge: auf welcher Seite der Liste Sie sind, was ins Suchfeld getippt wurde, welche Zeilen angehakt sind. Dieses Gedächtnis ist der Bildschirmzustand, und er wird einmal am Bildschirmrahmen deklariert.
Fügen Sie bei ausgewähltem Bildschirmrahmen auf der Registerkarte Bildschirm unter Zustand Folgendes hinzu:
| Name | Beginnt als |
|---|---|
cases | [] |
caseTotal | 0 |
page | 0 |
pageSize | 20 |
picked | "" |
pickedCount | 0 |
pickedId | "" |
form | { par_name: "", par_urgent: false, par_notes: "" } |
Deklarieren Sie die Form von form, lassen Sie es nicht bei {}. Eine Bindung, die ein Element
liest, das ein Objekt nicht hat, löst einen Fehler aus, und die erste Auswertung des Bildschirms läuft,
bevor irgendetwas das Formular ausgefüllt hat.
5. Die Liste füllen
Suchen Sie, weiterhin am Bildschirmrahmen, auf der Registerkarte Bildschirm die Handler, und setzen Sie Folgendes in Geladen:
loadRecords("par_case", "cases", {
top: getState("pageSize"),
skip: getState("page") * getState("pageSize"),
orderBy: "par_name",
countInto: "caseTotal"
});
Eine Zeile Abfrage ist die ganze Seitennavigation: top und skip sind die Seite, und countInto
bringt zurück, wie viele Zeilen es insgesamt gibt – was eine Seite mit zwanzig nicht sagen kann und eine
Schaltfläche Weiter wissen muss. Den Rest finden Sie unter
Eine Liste seitenweise anzeigen.
Noch wird nichts angezeigt. Es ist nichts gezeichnet, worin es angezeigt werden könnte.
6. Eine Zeile, einmal gezeichnet
Das ist der Schritt, der Menschen überrascht, deshalb lohnt es sich, es klar zu sagen: Sie zeichnen eine Zeile, und die Plattform zeichnet eine pro Datensatz.
-
Zeichnen Sie im Bildschirm einen Rahmen für die Liste – volle Inhaltsbreite, einige hundert Pixel hoch. Nennen Sie ihn
Rows. Setzen Sie auf der Registerkarte Bildschirm Dieses Objekt ist → Eine Liste und Inhalt, der nicht passt → Dorthin scrollen, dann In welche Richtung es scrollt → Nach unten. Ein Kasten, der für sechs Zeilen gezeichnet ist, fasst hundert, sobald eine echte Tabelle dahinter steht. -
Geben Sie ihm auf der Registerkarte Grafik ein automatisches Layout, vertikal. Ohne das landet jede Kopie der Zeile auf der ersten.
-
Zeichnen Sie einen Rahmen innerhalb von
Rows, volle Breite, 64 hoch. Nennen Sie ihnCase row, und setzen Sie Dieses Objekt ist → Ein Listeneintrag. -
Suchen Sie bei ausgewähltem
Case rowauf der Registerkarte Bildschirm Wiederholen für jedes, und tippen Sie:state.cases -
Zeichnen Sie in der Zeile ein Textobjekt für die Zusammenfassung. Wählen Sie es aus, und setzen Sie unter Bindungen Text:
row.par_name
row ist der Datensatz dieser Kopie. Speichern Sie, und drücken Sie Vorschau: eine Zeile pro
Fall, aus der Tabelle, ohne dass irgendetwas von Hand wiederholt wurde.
┌─ Rows ────────────────────────────────────────────────┐
│ ☐ 1 Sample case 1 Normal │ ← Case row, drawn once
│ ☐ 2 Sample case 2 High Urgent │
│ ☐ 3 Sample case 3 Low │
│ … │
└───────────────────────────────────────────────────────┘
7. Das Häkchen, und eine Vorstellung davon, was ausgewählt ist
Zeichnen Sie am Anfang der Zeile einen kleinen Rahmen, 20 × 20, und setzen Sie Steuerelement → Kontrollkästchen. Dann:
-
Bindungen → Wert:
state.picked.includes(row.id) -
Handler → Geändert:
var ids = "";var count = 0;var firstId = "";var i = 0;for (i = 0; i < state.cases.length(); i = i + 1) {var id = state.cases[i].id;var on = state.picked.includes(id);if (id == row.id) { on = !on; }if (on) {ids = ids + id + "|";count = count + 1;if (count == 1) { firstId = id; }}}setState("picked", ids);setState("pickedCount", count);setState("pickedId", firstId);
Der Wert ist ein Vergleich, kein Feld. Jedes Häkchen liest die eine Liste neu, sodass das Leeren der Liste alle auf einmal abhakt – was eine Markierung pro Zeile nie könnte, denn nichts wüsste, wo die anderen Zeilen sind.
8. Eine Symbolleiste, die aufwacht
Zeichnen Sie über der Liste eine Leiste – ein Rahmen, volle Breite, 56 hoch, Dieses Objekt ist → Ein Bereich – und setzen Sie drei Schaltflächen hinein. Für jede: Zeichnen Sie einen Rahmen, setzen Sie Steuerelement → Schaltfläche, und zeichnen Sie darin ein Textobjekt für die Beschriftung.
Setzen Sie auf jede ein Symbol. Wählen Sie die Schaltfläche aus, und verwenden Sie dann die
Symbolauswahl auf der Registerkarte Grafik – Plus, Pencil, Trash2. Was ankommt, ist ein
gewöhnlicher gezeichneter Pfad innerhalb der Schaltfläche, und die fertige Schaltfläche ordnet Symbol,
Abstand und Beschriftung selbst an.
| Schaltfläche | Bindungen → Aktiviert | Handler → Geklickt |
|---|---|---|
| Neu | (leer lassen) | setState("form", { par_name: "", par_urgent: false, par_notes: "" });openEndDrawer("New case"); |
| Bearbeiten | state.pickedCount == 1 | openStartDrawer("Edit case"); |
| Löschen | state.pickedCount > 0 | showModal("Confirm delete"); |
Binden Sie Aktiviert, statt Code zu schreiben, der Dinge ausgraut. Eine Bindung wird bei jeder Zustandsänderung neu ausgewertet, sodass die Leiste von selbst aufwacht und wieder still wird.
Färben Sie Text und Rahmen der Schaltfläche Löschen mit dem Token color.error ein, nicht mit einem
Rot, das Sie ausgewählt haben. Ein Token folgt dem Farbmodus des Lesers; ein Hex-Wert ist richtig für
die Person, die ihn gezeichnet hat, und falsch für alle, deren Design abweicht.
9. Der Seitenbereich, und was eine Overlay-Karte ist
Ein Overlay ist kein Bildschirm. Es ist eine Komponente, die Sie als Karte markieren, und ein Handler entscheidet, wo sie sich öffnet.
- Zeichnen Sie das Formular irgendwo abseits des Bildschirms – ein Rahmen, etwa 420 breit, mit einem Titel, den Feldern und zwei Schaltflächen. Wo auf der Zeichenfläche er liegt, spielt keine Rolle; eine Karte wird am Ursprung kompiliert, und nur ihre Breite bleibt erhalten.
- Wählen Sie den Rahmen aus, drücken Sie Komponente erstellen, und nennen Sie sie
New case. - Aktivieren Sie im Bereich der Komponente Eine Overlay-Karte.
┌─ Inspector · Component ───────────┐
│ ☑ An overlay card │
│ Show it with showModal("New │
│ case") … Its drawn width is │
│ the panel's width. │
│ │
│ ☐ It has to be answered │
│ Clicking outside, Escape and │
│ the close button all stop │
│ working while it is open. │
└───────────────────────────────────┘
Darin, für jedes Feld: Zeichnen Sie einen Rahmen, setzen Sie Steuerelement → Textfeld (oder
Textbereich für die Notizen), und binden Sie Wert an den Zustandspfad, den es bearbeitet –
state.form.par_name, state.form.par_notes. Ein Steuerelement, das an einen einfachen Zustandspfad
gebunden ist, schreibt dorthin zurück, es gibt also nichts weiter zu verdrahten.
Dann Geklickt der Schaltfläche Speichern:
if (getState("form").par_name == "") {
notifyError("A case needs a summary.");
} else {
createRecord("par_case", {
par_name: getState("form").par_name,
par_urgent: getState("form").par_urgent,
par_notes: getState("form").par_notes
});
notify("Case created.");
closeEndDrawer();
setState("page", 0);
loadRecords("par_case", "cases", { top: getState("pageSize"), skip: 0,
orderBy: "par_name", countInto: "caseTotal" });
}
Jeder Schreibvorgang endet damit, die Liste neu zu lesen. Nichts aktualisiert sich von selbst – der Bildschirm zeigt, was sein Zustand enthält, und der Zustand enthält, was die letzte Abfrage dort abgelegt hat.
Eine Frage, die beantwortet werden muss
Zeichnen Sie die Löschbestätigung auf dieselbe Weise, aktivieren Sie Eine Overlay-Karte und dann
zusätzlich Muss beantwortet werden. Ein Klick daneben, die Escape-Taste und die Schaltfläche
Schließen funktionieren dann nicht mehr – zeichnen Sie also Ihren eigenen Ausweg, eine Schaltfläche
Abbrechen, die closeModal() ausführt.
Lassen Sie dieses zweite Häkchen überall sonst weg. Ein Overlay, das jemand versehentlich geöffnet hat, sollte sich so schließen lassen, wie es sich geöffnet hat; nur das eine sollte sich weigern, bei dem ein Klick daneben keine Antwort ist.
10. Speichern, und sie wirklich öffnen
Drücken Sie Speichern. Oben erscheinen Warnungen, wenn der Compiler etwas bemerkt hat – eine Schaltfläche ohne Worte, ein fehlender Bildschirmrahmen, eine Bindung, die kein reiner Ausdruck ist. Sie nennen das Objekt, beheben Sie sie also, indem Sie es auswählen.
Verlassen Sie dann den Designer, und öffnen Sie die App aus der App-Liste der Shell. Die Vorschau ist nicht dasselbe: Sie stellt dieselben Bildschirme dar, aber ohne Umgebung dahinter, und was sie Ihnen daher nicht zeigen kann, sind Ihre Daten. Alles andere – die Seitenbereiche, die Kontrollkästchen, die Symbolleiste – verhält sich identisch.
Wie es weitergeht
- Ein zweiter Bildschirm. Zeichnen Sie neben dem ersten einen weiteren Rahmen, markieren Sie ihn als
Der Bildschirm, und benennen Sie ihn. Sobald es zwei gibt, erscheint in der Titelleiste eine
Auswahl Öffnet mit.
navigate("Board")wechselt zwischen ihnen. - Registerkarten. Eine Registerkartenleiste ist kein Steuerelement: Sie ist ein Zustandsfeld und
ein Bereich pro Wert. Zeichnen Sie die Bereiche im selben Rechteck, binden Sie Angezeigt jedes
Bereichs an
state.tab == "notes", und geben Sie den Registerkarten-Schaltflächen eine Bindung Ausgewählt mit demselben Vergleich. Verwenden Sie Nur auf diesem zeichnen in der Zeile einer Ebene, um einen Bereich unter den anderen zu erreichen. - Steuerelemente, die Sie nicht gezeichnet haben. Das Beispiel
studio-component-librarybringt eine Dropdownliste, ein Nachschlagefeld und einen Umschalter mit. Aktivieren Sie Veröffentlicht Komponenten bei dieser App, und sie erscheinen in Ihrer Palette – siehe Eine Komponente über Bildschirme hinweg teilen. - Ein Dashboard. Dieselbe Zeichenfläche zeichnet eines: siehe Ein Dashboard auf einem Bildschirm.
Fehlerbehebung
| Was Sie sehen | Was es ist |
|---|---|
| Only booleans are allowed in this expression | Ein optionales Feld wird als Bedingung gelesen. Umschließen Sie es: (state.x.par_urgent ?? false). |
| Die Bindung einer Zeile liest sich als leer | row existiert nur innerhalb des Elements, das Wiederholen für jedes trägt, und in seinen untergeordneten Elementen. |
| Zeilen stapeln sich übereinander | Der Kasten um die wiederholte Zeile braucht ein automatisches Layout. |
| Text läuft unten aus einem Kasten heraus | Setzen Sie ihn in einen Rahmen mit Dorthin scrollen → Nach unten, und verankern Sie die Worte oben. |
| Eine Dropdownliste schließt den Seitenbereich, aus dem sie geöffnet wurde | Behoben in 0.31. Aktualisieren Sie, oder verschieben Sie die Auswahl aus dem Seitenbereich. |
| Speichern ist deaktiviert | Seit dem letzten Speichern hat sich nichts geändert. |