Datastore e dati
Come una schermata carica, filtra e salva i dati — datastore di record e di elenco, chiavi, filtri, paginazione e i collegamenti ai dati.
Una schermata non parla direttamente con il database: parla con i datastore — contenitori di dati della schermata che caricano i record attraverso le API di tabella dell'app. I widget si collegano ai datastore: una Tabella mostra le righe di un datastore di elenco, i campi di un modulo leggono e scrivono in un datastore di record.
Questo è l'anello fra due capitoli: le API di tabella si creano sul modello dati (capitolo API & GraphQL); qui si collega la schermata a esse.
I due tipi di datastore
| Tipo | Che cosa carica | Per che cosa |
|---|---|---|
| Record | UN record (o un record nuovo, vuoto) | Moduli: i campi si collegano ai campi del record, e alla fine si salva. |
| Elenco | Una collezione di record | Tabelle, elenchi, card, grafici, kanban, calendari. |
I datastore possono vivere in due posti:
- Nella schermata — creati nell'inspector senza selezione, nella categoria Dati. Sono condivisi: più widget possono leggere dallo stesso, ed è ciò che si usa per i moduli e per le relazioni master-dettaglio.
- Dentro un widget — i widget di dati (Tabella, Grafico, KPI…) hanno il loro datastore nella loro categoria Dati. È il caso più comune per griglie e grafici indipendenti.
Il motore è lo stesso nei due posti; l'unica differenza sta nelle origini di valore disponibili nei filtri (vedi i collegamenti).
Creare un datastore nella schermata
- Clicca su una zona vuota del canvas perché l'inspector mostri la schermata.
- Nella categoria Dati, clicca su + record o + elenco.
- Clicca sul datastore creato per aprire il modale Configura datastore.
- Dagli un Nome del datastore — è con questo nome che i widget e il
codice lo trovano (es.:
conta,contas). - In API, scegli l'API che serve i dati. I campi dell'API restano disponibili per colonne, collegamenti e filtri. In un datastore di lista compaiono anche le API di pipeline, con il badge pipeline: restituiscono l'intera lista, senza filtri né paginazione.

Nota
Senza API di tabella pubblicate, il selettore avvisa: Nessuna API di tabella pubblicata in questa app. Crea prima l'API sull'entità del modello — è un passo del capitolo API & GraphQL.
Datastore di record — quale record caricare
Un datastore di record risponde a una domanda: quale record? La risposta si dà in Quale record caricare (chiave):
- Clicca su + campo della chiave.
- Scegli il campo (per impostazione predefinita, la chiave primaria), l'operatore e il valore —
tipicamente un Param del percorso: la schermata Scheda Account riceve
idnell' indirizzo e carica l'account con quell'id. - Più condizioni formano una chiave composta — devono corrispondere tutte.
Senza condizioni, il datastore carica un record nuovo (vuoto) — è così che
la stessa schermata di modulo serve anche per creare: aperta senza id, comincia in
bianco; salvata, fa l'inserimento.
Con condizioni che non trovano nessun record (un id che non esiste più, o
fuori dalla portata del ruolo di chi apre), l'app avvisa che il record
richiesto non esiste e il modulo non salva. Solo una chiave scritta in un
campo della schermata (una chiave naturale, come un codice articolo) resta
quella di un record nuovo.
Datastore di elenco — filtri e caricamento
Filtri (where)
I Filtri (where) sono condizioni applicate ogni volta che i dati vengono letti — è qui che si limita ciò che arriva dal database. Ogni condizione è campo / operatore / valore; + aggiungi filtro aggiunge condizioni e + gruppo crea sottogruppi annidati, con Tutte (AND) o Qualsiasi (OR) a decidere come si combinano.
Esempio da Gestione Clienti: la schermata Account filtra estado eq "activa";
il pannello "i miei account" aggiunge gestor eq → Sessione ▸ username.
Gli operatori:
| Operatore | Che cosa confronta |
|---|---|
eq / neq |
Uguale / diverso dal valore. neq include i record con il campo vuoto. |
contains, startsWith, endsWith |
Testo che contiene, inizia o finisce con il valore. |
gt, gte, lt, lte |
Maggiore, maggiore o uguale, minore, minore o uguale — numeri e date. |
in / nin |
Uno di / nessuno di una lista di valori. Il valore è una lista: più valori separati da virgole, o quello di una Lista con Selezione multipla collegata tramite Widget — è così che una tabella si filtra per più centri o più stati insieme. nin include i record con il campo vuoto. |
Una condizione con valore vuoto (casella di ricerca bianca, lista senza scelta) non filtra nulla — la schermata mostra tutto finché la persona non sceglie.
Ogni valore di un filtro si converte secondo il tipo della colonna: in una colonna di testo, un codice fiscale o un CAP («0012») restano testo, e in una colonna decimale «12,5» è un numero.
Caricamento e pagina
| Opzione | Che cosa fa |
|---|---|
| Carica tutto | Porta tutti i record del filtro in una volta — cambiare pagina, ordinare e filtrare nella schermata diventa istantaneo. |
| Una pagina per volta | Va al server a ogni cambio di pagina — per tabelle grandi, dove portare tutto non ha senso. |
| Per pagina | Quante righe si vedono per volta nella schermata — da non confondere con quanti record vengono letti. |
| Carica automaticamente | Leggere i dati appena la schermata si apre. Disattivalo se preferisci caricare solo dopo un'azione (un pulsante "Cerca", per esempio). |
Senza Carica automaticamente, l'elenco legge quando qualcuno glielo chiede:
un reload() (su un pulsante «Cerca», per esempio), un cambio di pagina o di
ordinamento, o un filtro applicato. Cambiare un campo della schermata non lo fa
leggere da solo.
Quando il filtro effettivo cambia (un campo della schermata, un parametro, lo stato dell'app), l'elenco torna alla prima pagina. Se la pagina in cui eri non esiste più (hai eliminato l'ultimo record dell'ultima pagina, per esempio), l'elenco passa all'ultima pagina esistente.
Suggerimento
In entrambe le modalità, usa i Filtri (where) per limitare ciò che viene letto. "Carica tutto" con un filtro decente è veloce; senza nessun filtro, è chiedere la tabella intera.
I collegamenti — da dove viene un valore
Ogni volta che un filtro, una chiave o una proprietà ha bisogno di un valore, usi lo stesso pezzo: il collegamento. Il primo selettore dice l'origine; il resto cambia a seconda di essa:
| Origine | Che cos'è |
|---|---|
| Fisso | Un valore scritto lì stesso, uguale per tutti. |
| Param | Un parametro del percorso della schermata (sezione Parametri del percorso). |
| Sessione | Un campo dell'utente con sessione avviata (userId, username, name). |
| Stato | Un valore salvato nella memoria dell'app con keplin.state.set() — disponibile in tutte le schermate. |
| Datastore | Un campo di un altro datastore della schermata — la base del master-dettaglio. |
| Widget | Il valore attuale di un altro widget di input — la base dei filtri interattivi. |
Anche un campo scrive nello stato: nel Collegamento ai dati del campo, scegli Stato e scrivi la Chiave. Un filtro con l'origine Stato e la stessa chiave rilegge i dati quando il valore cambia. È così che un'area widget della barra filtra le pagine; vedi Navigazione dell'app.
Le origini Datastore e Widget esistono solo nei datastore dentro i widget — dipendono dal resto della schermata. Nei datastore della schermata restano le quattro prime.
Con questi pezzi si montano gli schemi di tutti i giorni senza codice:
- Master-dettaglio — la tabella delle opportunità dell'account: nel datastore della
tabella, filtro
contaId eq→ Datastore ▸conta▸id. Selezionare un altro account ricarica il dettaglio. - Filtro per testo — una Casella di testo "cerca" e, nel datastore della
tabella,
nome contains→ Widget ▸ la casella. (Per filtrare solo cliccando su un pulsante, si fa per evento — vedi Eventi e SDK.)
Collegare i campi di modulo a un record
Ogni campo di modulo ha, nella categoria Dati, la sezione Collegamento ai dati: scegli il datastore di record e il campo. Da lì in poi l'input mostra il valore caricato e le modifiche restano nel datastore — da salvare — finché qualcuno non salva.
Il passo finale è un pulsante il cui evento salva:
const ok = await keplin.data.store("conta").save();
if (ok) {
keplin.ui.toast("Salvato.", "success");
}
Questo codice è esattamente ciò che l'azione predefinita Salva datastore dell'
editor di eventi inserisce per te. save() valida prima (obbligatori,
regole, script di validazione) e salva solo se passa tutto; restituisce true se
ha salvato.
Quando salvi un record che esisteva già, partono solo i campi cambiati da quando è stato letto. Un campo svuotato si salva vuoto (nullo nel database), e in un campo decimale «12,5» si legge come numero.

Con modifiche non salvate, uscire dalla pagina chiede conferma: dai menu,
dal pulsante Indietro del browser o chiudendo la scheda. Un modal lo
chiedeva già alla chiusura. La navigazione fatta via codice (keplin.nav.go)
non chiede nulla: chi la chiama ha già deciso, e spesso ha appena salvato.
Salvando un record nuovo, un campo che la schermata non mostra non viene
inviato: in una colonna con un valore predefinito nel database, o generata dal
database, resta quel valore; una colonna obbligatoria senza valore predefinito
deve stare nella schermata, e il modulo dice quale manca. Una chiave scritta
in un campo della schermata (una chiave naturale, come un codice articolo) è
quella di un record nuovo; impostata da codice con set(), resta quella di un
record da modificare. Salvare un record che nel frattempo non esiste più dà
errore, e non «Salvato».
Il modale Configura datastore, campo per campo

| Campo | Record | Elenco |
|---|---|---|
| Nome del datastore | ✓ | ✓ |
| API | ✓ | ✓ |
| Quale record caricare (chiave) | ✓ | — |
| Filtri (where) | — | ✓ |
| Caricamento / Per pagina | — | ✓ |
| Carica automaticamente | ✓ | ✓ |
Datastore in schermate pubbliche
In una schermata marcata Schermata pubblica (senza sessione), i dati arrivano solo da API con lettura pubblica: il selettore mostra solo quelle, e un'API già scelta che non sia pubblica viene segnalata — Questa API non ha lettura pubblica — in una schermata senza sessione non carica dati. La lettura si marca come pubblica nell' editor dell'API.
I dati nel codice
Tutto ciò che i datastore fanno è anche nell'SDK degli eventi —
keplin.data.store("nome") restituisce il datastore per nome, con reload(),
setWhere(), get()/set()/save() e compagnia. Il capitolo
Eventi e SDK lo percorre.
Perché no…?
- Perché non carica i dati? Guarda, in ordine: Carica automaticamente è attivo? L'API scelta esiste ed è pubblicata? In una schermata pubblica, la lettura dell'API è pubblica? Il filtro non sta escludendo tutto?
- Perché apre sempre un record vuoto? Il datastore di record non ha condizioni in Quale record caricare (chiave) — oppure il parametro usato nella condizione non sta arrivando nel percorso.
- Perché ho cambiato il modello e la colonna nuova non appare? Il datastore conserva una fotografia dei campi dell'API di quando l'hai scelta. Riapri Configura datastore e riscegli l'API per aggiornare la fotografia. Ciò che ogni colonna già scelta è (tipo, obbligatorietà, valore predefinito, data) si aggiorna da solo all'apertura della schermata; solo le colonne nuove vanno scelte.
- Perché la paginazione è lenta? Sei in Una pagina per volta con molti viaggi al server — oppure in Carica tutto senza filtri su una tabella enorme. Adatta la modalità alla dimensione reale dei dati.