Datastores und Daten
Wie ein Bildschirm Daten lädt, filtert und speichert — Datensatz- und Listen-Datastores, Schlüssel, Filter, Paginierung und die Datenbindungen.
Ein Bildschirm spricht nicht direkt mit der Datenbank: Er spricht mit Datastores — Datencontainern des Bildschirms, die Datensätze über die Tabellen-APIs der App laden. Die Widgets binden sich an die Datastores: Eine Tabelle zeigt die Zeilen eines Listen-Datastores, die Felder eines Formulars lesen und schreiben in einem Datensatz-Datastore.
Das ist das Bindeglied zwischen zwei Kapiteln: Die Tabellen-APIs werden über dem Datenmodell angelegt (Kapitel APIs & GraphQL); hier wird der Bildschirm an sie gebunden.
Die zwei Arten von Datastore
| Art | Was sie lädt | Wofür |
|---|---|---|
| Datensatz | EINEN Datensatz (oder einen neuen, leeren) | Formulare: Die Felder binden sich an die Felder des Datensatzes, und am Ende wird gespeichert. |
| Liste | Eine Sammlung von Datensätzen | Tabellen, Listen, Karten, Diagramme, Kanbans, Kalender. |
Datastores können an zwei Orten leben:
- Auf dem Bildschirm — im Inspektor ohne Auswahl angelegt, in der Kategorie Daten. Sie sind geteilt: Mehrere Widgets können aus demselben lesen, und das ist es, was man für Formulare und für Master-Detail-Beziehungen verwendet.
- In einem Widget — die Daten-Widgets (Tabelle, Diagramm, KPI…) haben ihren eigenen Datastore in ihrer Kategorie Daten. Das ist der häufigste Fall für eigenständige Grids und Diagramme.
Die Maschinerie ist an beiden Orten dieselbe; der einzige Unterschied liegt in den Wertquellen, die in den Filtern verfügbar sind (siehe die Bindungen).
Einen Datastore auf dem Bildschirm anlegen
- Klicken Sie auf eine leere Zone des Canvas, damit der Inspektor den Bildschirm zeigt.
- Klicken Sie in der Kategorie Daten auf + Datensatz oder + Liste.
- Klicken Sie auf den angelegten Datastore, um das Modal Datastore konfigurieren zu öffnen.
- Geben Sie ihm einen Name des Datastores — unter diesem Namen finden ihn
die Widgets und der Code (z. B.
conta,contas). - Wählen Sie unter API die API, die die Daten liefert. Die Felder der API stehen dann für Spalten, Bindungen und Filter zur Verfügung. In einem Listen-Datastore erscheinen auch die Pipeline-APIs, mit dem Abzeichen pipeline: Sie liefern die ganze Liste, ohne Filter oder Seiten.

Hinweis
Ohne veröffentlichte Tabellen-APIs weist der Selektor darauf hin: Keine veröffentlichten Tabellen-APIs in dieser App. Legen Sie zuerst die API über der Entität des Modells an — das ist ein Schritt aus dem Kapitel APIs & GraphQL.
Datensatz-Datastore — welcher Datensatz geladen wird
Ein Datensatz-Datastore antwortet auf eine Frage: welcher Datensatz? Die Antwort geben Sie unter Welcher Datensatz geladen wird (Schlüssel):
- Klicken Sie auf + Schlüsselfeld.
- Wählen Sie das Feld (standardmäßig der Primärschlüssel), den Operator und den
Wert — typischerweise ein Param der Route: Der Bildschirm
Kontodatenblatt erhält
idin der Adresse und lädt das Konto mit dieser id. - Mehrere Bedingungen bilden einen zusammengesetzten Schlüssel — alle müssen passen.
Ohne Bedingungen lädt der Datastore einen neuen (leeren) Datensatz — so
taugt derselbe Formularbildschirm auch zum Anlegen: ohne id geöffnet, beginnt
er leer; gespeichert, macht er das Insert.
Finden die Bedingungen keinen Datensatz (eine id, die nicht mehr existiert
oder außerhalb der Reichweite der Rolle liegt, die den Bildschirm öffnet),
meldet die App, dass der angeforderte Datensatz nicht existiert, und das
Formular speichert nicht. Nur ein Schlüssel, der in ein Feld des Bildschirms
eingegeben wird (ein natürlicher Schlüssel, etwa eine Artikelnummer), bleibt
der Schlüssel eines neuen Datensatzes.
Listen-Datastore — Filter und Laden
Filter (where)
Die Filter (where) sind Bedingungen, die bei jedem Lesen der Daten gelten — hier wird begrenzt, was aus der Datenbank kommt. Jede Bedingung besteht aus Feld / Operator / Wert; + Filter hinzufügen ergänzt Bedingungen, und + Gruppe erzeugt verschachtelte Untergruppen, wobei Alle (AND) oder Beliebige (OR) entscheidet, wie sie sich verbinden.
Beispiel aus der Kundenverwaltung: Der Bildschirm Konten filtert
estado eq "activa"; das Panel „meine Konten“ ergänzt gestor eq →
Sitzung ▸ username.
Die Operatoren:
| Operator | Was er vergleicht |
|---|---|
eq / neq |
Gleich / ungleich dem Wert. neq schließt Datensätze mit leerem Feld ein. |
contains, startsWith, endsWith |
Text, der den Wert enthält, damit beginnt oder endet. |
gt, gte, lt, lte |
Größer, größer oder gleich, kleiner, kleiner oder gleich — Zahlen und Daten. |
in / nin |
Eines von / keines von einer Werteliste. Der Wert ist eine Liste: mehrere durch Kommas getrennte Werte oder der Wert einer Liste mit Mehrfachauswahl, gebunden über Widget — so wird eine Tabelle nach mehreren Zentren oder mehreren Zuständen zugleich gefiltert. nin schließt Datensätze mit leerem Feld ein. |
Eine Bedingung mit leerem Wert (leeres Suchfeld, Liste ohne Auswahl) filtert nichts — der Bildschirm zeigt alles, bis die Person wählt.
Jeder Filterwert wird nach dem Typ der Spalte umgewandelt: In einer Textspalte bleiben eine Steuernummer oder eine Postleitzahl („0012“) Text, und in einer Dezimalspalte ist „12,5“ eine Zahl.
Laden und Seite
| Option | Was sie tut |
|---|---|
| Alles laden | Holt alle Datensätze des Filters auf einmal — Blättern, Sortieren und Filtern auf dem Bildschirm wird sofort wirksam. |
| Seite für Seite | Geht bei jedem Seitenwechsel zum Server — für große Tabellen, bei denen alles zu holen keinen Sinn ergibt. |
| Pro Seite | Wie viele Zeilen auf dem Bildschirm gleichzeitig zu sehen sind — nicht zu verwechseln damit, wie viele Datensätze gelesen werden. |
| Automatisch laden | Die Daten lesen, sobald der Bildschirm geöffnet wird. Schalten Sie es aus, um erst nach einer Aktion zu laden (etwa einem Button „Suchen“). |
Ohne Automatisch laden liest die Liste, wenn jemand sie dazu auffordert: ein
reload() (etwa auf einer Schaltfläche „Suchen“), ein Seiten- oder
Sortierwechsel oder ein angewendeter Filter. Ein geändertes Feld auf dem
Bildschirm lässt sie nicht von selbst lesen.
Wenn sich der wirksame Filter ändert (ein Feld auf dem Bildschirm, ein Parameter, der App-Zustand), springt die Liste zur ersten Seite zurück. Existiert die Seite, auf der Sie waren, nicht mehr (etwa weil Sie den letzten Datensatz der letzten Seite gelöscht haben), wechselt die Liste zur letzten vorhandenen Seite.
Tipp
Nutzen Sie in beiden Modi die Filter (where), um zu begrenzen, was gelesen wird. „Alles laden“ mit einem anständigen Filter ist schnell; ohne jeden Filter heißt es, die ganze Tabelle anzufordern.
Die Bindungen — woher ein Wert kommt
Immer wenn ein Filter, ein Schlüssel oder eine Eigenschaft einen Wert braucht, verwenden Sie dasselbe Teil: die Bindung. Der erste Selektor nennt die Quelle; der Rest ändert sich mit ihr:
| Quelle | Was sie ist |
|---|---|
| Fest | Ein Wert, der direkt dort eingetragen wird, gleich für alle. |
| Param | Ein Parameter der Route des Bildschirms (Abschnitt Routen-Parameter). |
| Sitzung | Ein Feld des angemeldeten Benutzers (userId, username, name). |
| Zustand | Ein Wert, der mit keplin.state.set() im Speicher der App abgelegt wird — auf jedem Bildschirm verfügbar. |
| Datastore | Ein Feld aus einem anderen Datastore des Bildschirms — die Grundlage von Master-Detail. |
| Widget | Der aktuelle Wert eines anderen Eingabe-Widgets — die Grundlage interaktiver Filter. |
Auch ein Feld schreibt in den Zustand: Wählen Sie in der Datenbindung des Feldes die Option Zustand und geben Sie den Schlüssel ein. Ein Filter mit der Quelle Zustand und demselben Schlüssel liest die Daten neu, wenn sich der Wert ändert. So filtert ein Widget-Bereich der Leiste die Seiten; siehe Navigation der App.
Die Quellen Datastore und Widget gibt es nur in den Datastores innerhalb von Widgets — sie hängen vom Rest des Bildschirms ab. In den Datastores des Bildschirms bleiben die ersten vier.
Mit diesen Teilen baut man die Alltagsmuster ohne Code:
- Master-Detail — die Opportunity-Tabelle des Kontos: im Datastore der
Tabelle der Filter
contaId eq→ Datastore ▸conta▸id. Ein anderes Konto auszuwählen lädt das Detail neu. - Filter über Text — ein Textfeld „suchen“ und, im Datastore der Tabelle,
nome contains→ Widget ▸ das Textfeld. (Um erst beim Klick auf einen Button zu filtern, geht man über ein Ereignis — siehe Ereignisse und das SDK.)
Formularfelder an einen Datensatz binden
Jedes Formularfeld hat in der Kategorie Daten den Abschnitt Datenbindung: Wählen Sie den Datensatz-Datastore und das Feld. Von da an zeigt die Eingabe den geladenen Wert, und die Änderungen bleiben im Datastore — ungespeichert — bis jemand speichert.
Der letzte Schritt ist ein Button, dessen Ereignis speichert:
const ok = await keplin.data.store("conta").save();
if (ok) {
keplin.ui.toast("Gespeichert.", "success");
}
Dieser Code ist genau das, was die vordefinierte Aktion Datastore speichern
des Ereignis-Editors für Sie einfügt. save() validiert zuerst (Pflichtfelder,
Regeln, Validierungsskripte) und speichert nur, wenn alles besteht; es gibt
true zurück, wenn gespeichert wurde.
Beim Speichern eines bereits vorhandenen Datensatzes werden nur die Felder gesendet, die sich seit dem Lesen geändert haben. Ein geleertes Feld wird leer gespeichert (NULL in der Datenbank), und in einem Dezimalfeld wird „12,5“ als Zahl gelesen.

Mit ungespeicherten Änderungen fragt das Verlassen der Seite nach einer
Bestätigung: über die Menüs, über die Zurück-Schaltfläche des Browsers oder
beim Schließen des Tabs. Ein Modal fragte schon beim Schließen. Navigation
per Code (keplin.nav.go) fragt nicht: Wer sie aufruft, hat schon
entschieden und oft gerade gespeichert.
Beim Speichern eines neuen Datensatzes wird ein Feld, das der Bildschirm nicht
zeigt, nicht gesendet: In einer Spalte mit Standardwert in der Datenbank, oder
von ihr erzeugt, gilt dieser Wert; eine Pflichtspalte ohne Standardwert muss
auf dem Bildschirm sein, und das Formular sagt, welche fehlt. Ein in ein Feld
des Bildschirms eingegebener Schlüssel (ein natürlicher Schlüssel, etwa ein
Artikelcode) gehört zu einem neuen Datensatz; per Code mit set() gesetzt,
bleibt er der Schlüssel eines zu ändernden Datensatzes. Einen inzwischen nicht
mehr existierenden Datensatz zu speichern ergibt einen Fehler statt
„Gespeichert“.
Das Modal Datastore konfigurieren, Feld für Feld

| Feld | Datensatz | Liste |
|---|---|---|
| Name des Datastores | ✓ | ✓ |
| API | ✓ | ✓ |
| Welcher Datensatz geladen wird (Schlüssel) | ✓ | — |
| Filter (where) | — | ✓ |
| Laden / Pro Seite | — | ✓ |
| Automatisch laden | ✓ | ✓ |
Datastores auf öffentlichen Bildschirmen
Auf einem als Öffentlicher Bildschirm (ohne Sitzung) markierten Bildschirm kommen die Daten ausschließlich aus APIs mit öffentlichem Lesezugriff: Der Selektor zeigt nur diese, und eine bereits gewählte API, die nicht öffentlich ist, wird gekennzeichnet — Diese API hat keinen öffentlichen Lesezugriff — auf einem Bildschirm ohne Sitzung lädt sie keine Daten. Der Lesezugriff wird im API-Editor als öffentlich markiert.
Die Daten im Code
Alles, was die Datastores tun, steht auch im SDK der Ereignisse —
keplin.data.store("name") gibt den Datastore über seinen Namen zurück, mit
reload(), setWhere(), get()/set()/save() und Gefährten. Das Kapitel
Ereignisse und das SDK geht es durch.
Warum nicht…?
- Warum lädt es keine Daten? Prüfen Sie in dieser Reihenfolge: Ist Automatisch laden eingeschaltet? Existiert die gewählte API und ist sie veröffentlicht? Ist auf einem öffentlichen Bildschirm der Lesezugriff der API öffentlich? Schließt der Filter nicht alles aus?
- Warum öffnet sich immer ein leerer Datensatz? Der Datensatz-Datastore hat keine Bedingungen unter Welcher Datensatz geladen wird (Schlüssel) — oder der in der Bedingung verwendete Parameter kommt in der Route nicht an.
- Warum erscheint die neue Spalte nicht, nachdem ich das Modell geändert habe? Der Datastore hält ein Abbild der Felder der API von dem Moment, in dem Sie sie gewählt haben. Öffnen Sie Datastore konfigurieren erneut und wählen Sie die API neu, um das Abbild zu aktualisieren. Was jede bereits gewählte Spalte ist (Typ, Pflicht oder nicht, Standardwert, Datum), aktualisiert sich beim Öffnen des Bildschirms von selbst; nur neue Spalten müssen gewählt werden.
- Warum ist die Paginierung langsam? Sie sind in Seite für Seite mit vielen Gängen zum Server — oder in Alles laden ohne Filter in einer riesigen Tabelle. Passen Sie den Modus an die echte Größe der Daten an.