Hendelser og SDK-et
Hendelsene til widgetene og skjermen, kodeeditoren, de forhåndsdefinerte handlingene og keplin-SDK-et i TypeScript — data, widgets, navigasjon, økt, modaler og arbeidsflyter.
Mye skjerm lages uten å skrive en eneste linje: binde en datastore, dra ut widgets, peke en knapp mot en annen skjerm. Men før eller senere dukker det opp et «når dette skjer, gjør hint» — lagre og gå tilbake, laste en tabell på nytt etter et filter, bekrefte før sletting, åpne en modal og bruke det den ga tilbake.
Det er det hendelsene er til: punkter på skjermen der din egen kode
kjører, skrevet i TypeScript, med et SDK — objektet keplin — som gir
tilgang til alt skjermen har.
Hvor hendelsene er
I inspektøren heter den siste kategorien til en widget (og til selve skjermen) Hendelser. Den har én rad per tilgjengelig hendelse, og på hver rad:
- et punkt til venstre: fylt når den hendelsen allerede har kode, tomt når den ikke har;
- en knapp … til høyre, som åpner editoren.

Navnene på hendelsene oversettes ikke — de er de samme på alle språk
(onClick, onRowClick, onLoad), fordi de også er navnene som dukker
opp i koden og i oppføringene i Radar.
Hendelsene til skjermen
Klikk på et tomt område på canvaset så inspektøren viser skjermen. Kategorien Hendelser har tre:
| Hendelse | Når den utløses | Til hva |
|---|---|---|
onLoad |
Én gang, når skjermen åpnes. | Forberede tilstand, laste ting datastorene ikke laster, ønske velkommen. |
onParamsChange |
Hver gang ruteparameterne endres — og ikke ved første åpning. | Reagere på et postbytte uten å åpne skjermen på nytt. |
onUnload |
Når skjermen forlates. | Rydde tilstand, lagre utkast. |

Hendelsene til hver widget
Hver widgettype deklarerer sine. I tillegg til navnet er det payloaden
som teller — dataene hendelsen bringer med seg, og som koden leser i
keplin.event.
Skjemafelt
| Widget | Hendelser | keplin.event |
|---|---|---|
| Tekstfelt, Tekstområde, Tall, Ja/nei, Nedtrekksliste, Dato, Farge | onChange |
{ value } |
| Filopplasting | onChange, onUpload |
onUpload: { file, name } |
Handlinger og navigasjon
| Widget | Hendelser | keplin.event |
|---|---|---|
| Knapp | onClick |
{} |
| Knapp med meny | onClick, onMenuItem |
onMenuItem: { id, label } |
| Lenke | onClick |
{} |
| Eksport | onExport, onDataLoaded |
onExport: { rows, filename } |
Struktur og innhold
| Widget | Hendelser | keplin.event |
|---|---|---|
| Faner | onTabChange |
{ tab } |
| Rapport | onLoad |
{ report } |
Datawidgets
| Widget | Hendelser | keplin.event |
|---|---|---|
| Tabell | onRowClick, onRowDoubleClick, onSelectionChange, onDataLoaded |
{ row, index } · onSelectionChange: { row, rows } |
| Liste, Kort | onRowClick, onDataLoaded |
{ row, index } |
| Diagram | onClick |
{ name, seriesName, value, dataIndex } |
| KPI | onClick, onDataLoaded |
{ value, indicatorId } |
Tavler og planlegging
| Widget | Hendelser | keplin.event |
|---|---|---|
| Kanban | onCardClick, onCardCreate, onCardMoved, onDataLoaded |
{ row } · { column } · { row, from, to, index } |
| Kalender | onEventClick, onDayClick, onRangeSelect, onRangeChange, onDataLoaded |
{ row } · { date } · { start, end } · { start, end, view } |
| Gantt | onBarClick, onEmptyClick, onDataLoaded |
{ row } · { date } |
Prosesser
| Widget | Hendelser | keplin.event |
|---|---|---|
| Status for prosessen | onDecide |
{ task, outcome } |
| Mine oppgaver | onOpen, onDecide |
{ task, screenId } |
Nota
Widgets programmert av deg (de som vises i paletten under Egendefinert) deklarerer sine egne hendelser, og de dukker opp her som alle andre.
Kodeeditoren
Knappen … for en hendelse åpner editoren i en modal. Tittelen sier
hvor du er: id-en til widgeten (eller navnet på skjermen) og navnet på
hendelsen — w_fic_sav1 · onClick.

| Knapp | Hva den gjør |
|---|---|
| Sett inn handling | Skriver koden for en vanlig oppgave for deg (nedenfor). |
| Fjern handler | Sletter koden til denne hendelsen. Punktet blir tomt igjen. |
| Avbryt | Lukker uten å lagre. |
| Lagre | Sjekker og lagrer. |
Editoren har forslag mens du skriver (Ctrl+mellomrom): hele
keplin er deklarert, med riktige typer — og, enda bedre, id-ene til
widgetene på denne skjermen ligger der inne. Å skrive
keplin.widgets.get(" viser listen over widgetene på skjermen, og en id
som ikke finnes markeres som feil før du lagrer.
Atenção
Ved lagring kompileres koden. Er den ikke kjørbar, avviser plattformen den — Hendelsen ble ikke lagret: koden lar seg ikke kjøre — og modalen blir stående åpen så du kan rette. En skjerm blir aldri stående med ødelagt kode inni.
De forhåndsdefinerte handlingene
Sett inn handling åpner en liste over de vanligste oppgavene. Du velger en, og koden skrives på slutten av det som allerede ligger der, allerede med de virkelige navnene fra skjermen din — den første post-datastoren, den første tabellen, det første tekstfeltet.

| Handling | Hva den skriver |
|---|---|
| Lagre datastore | Validerer og lagrer posten, med suksessvarsel. |
| Last inn datastore på nytt | Leser dataene i en datastore på nytt. |
| Filtrer datastore (på tekst) | Leser teksten i et felt og bruker den som filter. |
| Naviger til en skjerm | Hopper til en annen rute i appen. |
| Last inn en tabell på nytt | Oppdaterer dataene i en tabellwidget. |
| Filtrer tabell på verdien i et tekstfelt | Det klassiske interaktive filteret. |
| Vis/skjul en widget | Veksler synligheten til en widget. |
| Bekreft og vis en toast | Spør før den handler og varsler til slutt. |
| Start en arbeidsflyt | Setter en prosess i gang på den gjeldende posten. |
| Se og fullfør oppgaver | Lister oppgavene til den som bruker appen og beslutter én. |
| Send et signal til en arbeidsflyt | Vekker prosesser som sto og ventet. |
| Logg ut | Går ut av appen. |
Den innsatte koden er et utgangspunkt: den er din, og den er til å redigere. Den genereres ikke på nytt.
Hvordan koden kjører
Hver hendelse er en asynkron funksjon som mottar én eneste ting:
keplin. Av det følger tre praktiske konsekvenser:
awaitfungerer øverst i koden. Ingenting trenger å pakkes inn.returngår ut av hendelsen. Det er den normale måten å gi seg halvveis på (for eksempel når en bekreftelse ble avslått).- Det finnes ingen parametere. Konteksten ligger inne i selve
keplin:keplin.eventbringer payloaden ogkeplin.ctxsier hvor du er (ctx.widgeter widgeten som utløste —nulli skjermhendelser —,ctx.eventer navnet på hendelsen ogctx.screenskjermen).
Så lenge koden til en knapp ikke er ferdig, viser knappen tre animerte prikker: den som bruker appen skjønner at den jobber. Hvis koden sprekker, går ikke skjermen i stykker: det vises et varsel og feilen registreres i Radar, med skjermen, widgeten og hendelsen der det skjedde.
SDK-et keplin
Alt koden kan gjøre ligger under keplin. Dette er områdene:
| Område | Til hva |
|---|---|
keplin.event / keplin.ctx |
Payloaden til hendelsen og konteksten den kjører i. |
keplin.widgets |
Snakke med widgetene på skjermen. |
keplin.data |
Datastorene: lese, skrive, filtrere, lagre. |
keplin.nav |
Navigere og lese ruteparameterne. |
keplin.ui |
Varsler, bekreftelser og modaler. |
keplin.state |
Tilstand delt mellom skjermer. |
keplin.session |
Hvem som bruker appen, og hva vedkommende kan gjøre. |
keplin.auth |
Pålogging, registrering og gjenoppretting av passord (systemskjermer). |
keplin.i18n |
Oversatte setninger. |
keplin.storage |
Preferanser lagret på enheten. |
keplin.api |
Kalle API-ene i appen direkte. |
keplin.reports |
Åpne og laste ned rapporter. |
keplin.workflow |
Starte prosesser, liste og fullføre oppgaver. |
Widgetene
keplin.widgets.get("id") gir tilbake handle-et til en widget. Alle
handles har det samme grunnlaget:
const w = keplin.widgets.get("w_fic_tel1");
w.show(); // vise
w.hide(); // skjule
w.setEnabled(false); // deaktivere
w.set("label", "Telemóvel"); // endre en hvilken som helst egenskap fra inspektøren
w.get("label"); // lese den effektive verdien
w.reset(); // glemme endringene gjort i kjøring
Og deretter legger hver familie til det som er dens eget:
| Familie | Hva den legger til |
|---|---|
| Skjemafelt | getValue(), setValue(v), validate(), error |
| Datawidgets (Tabell, Liste, Kort, Diagram, KPI, Kanban, Kalender, Gantt) | rows, total, refresh(), setFilter(where), setSort(sort) |
| Tabell | selectedRow, selectedRows, clearSelection() |
| KPI | value, values, valueOf(indikatorId) |
| Kanban | columns, moveCard(id, kolonne, indeks?) |
| Kalender | view, start, end, goTo(dato), setView(visning) |
| Gantt | zoom, setZoom(z) |
| Faner | activeTab, tab("id") — og, på fanen, activate(), show(), hide(), setEnabled() |
| Etikett / Knapp / Lenke / Brødsmulesti | setText(t) / setLabel(t) |
| Markdown | setContent(md) |
| Ekstern side | setUrl(url), reload() |
| Eksport | export() |
| Rapport | url, download() |
Nota
Forslagene i editoren tilbyr alle verbene fra alle familiene, fordi
editoren ikke vet på forhånd hvilken widget den id-en er. I kjøring
finnes bare de som hører til den virkelige typen — moveCard på en
Knapp gjør ingenting nyttig.
Dataene
keplin.data.store("navn") gir tilbake en datastore på skjermen etter
navnet (se
Datastorer og data).
I en post-datastore:
const conta = keplin.data.store("conta");
conta.get("nome"); // lese et felt
conta.set("estado", "ativo"); // skrive et felt (blir stående ulagret)
conta.record(); // hele posten
conta.isDirty(); // finnes det ulagrede endringer?
conta.reset(); // kaste endringene
const ok = await conta.save(); // validerer og lagrer; true hvis lagret
I en liste-datastore:
const contas = keplin.data.store("contas");
contas.rows(); // de innlastede radene
contas.total(); // totalen (når serveren gir den)
contas.reload(); // lese på nytt
contas.setWhere({ estado: { eq: "ativo" } }); // ekstra filter; null tømmer
contas.setSort([{ field: "nome", direction: "ASC" }]);
contas.goToPage(2);
I begge sier status() hvordan innlastingen står (idle, loading,
ready, error).
Navigasjon
keplin.nav.go("/ficha-de-conta/17"); // gå til en rute (med parametere)
keplin.nav.back(); // gå tilbake
keplin.nav.params; // parameterne til den gjeldende skjermen, etter navn
Varsler, bekreftelser og modaler
keplin.ui.toast("Gravado.", "success"); // "success" | "error" | "info"
const ok = await keplin.ui.confirm("Apagar o registo?");
if (!ok) return;
Bekreftelsen er en dialog med temaet til appen — aldri den grå boksen fra nettleseren.
Tilstand, økt og preferanser
keplin.state.set("filtroContas", "activas"); // lever så lenge fanen er åpen
keplin.state.get("filtroContas");
keplin.state.remove("filtroContas");
keplin.session.user; // { id, username, name } — null på offentlige skjermer
keplin.session.roles; // rollene til den som bruker appen
keplin.session.can("contas.editar"); // har vedkommende denne handlingen? (Innstillinger ▸ Tillatelser)
await keplin.session.logout();
keplin.storage.set("colunasContas", ["nome", "cidade"]); // blir på enheten
keplin.storage.get("colunasContas");
Dica
For å avgjøre hva noen kan gjøre, spør keplin.session.can("...") og
ikke hasRole("gestor"). Handlingene deklareres under Innstillinger ▸
Tillatelser og overlever omorganiseringer av roller; navnet på en
rolle gjør det ikke.
API-ene og rapportene
const linhas = await keplin.api.query("contas", { estado: "ativo" }, ["id", "nome"]);
await keplin.api.mutate("criarConta", { nome: "Nova" }, ["id"]);
keplin.reports.open("Contactos da conta", { contaId: 17 });
keplin.reports.download("Contactos da conta", { contaId: 17 }, "xlsx");
I en spørring er feltlisten påkrevd — det er den som sier hva du vil hente.
Atenção
keplin.reports.open åpner en ny fane og kan derfor ikke stå bak en
await: utenfor brukerens gest blokkerer nettleseren vinduet. Åpne
først, gjør resten etterpå.
Arbeidsflyter
const registo = keplin.data.store("oportunidade").get("id");
await keplin.workflow.start("wf_aprovacao", registo);
const tarefas = await keplin.workflow.tasks();
await keplin.workflow.complete(tarefas[0].id, "aprovar");
const { woken } = await keplin.workflow.signal("documento-recebido", registo);
Oversatte setninger
keplin.i18n.t("{n} contas activas", { n: linhas.length });
keplin.i18n.locale;
Modale skjermer
En Keplin-skjerm er ikke modal fordi den ble åpnet på en viss måte — den er modal fordi den ble konfigurert slik. Beslutningen ligger i inspektøren for skjermen, i kategorien Presentasjon:

| Alternativ | Hva det gjør |
|---|---|
| Modus | Skjerm (en vanlig side), Modal (midtstilt) eller Sidepanel (høyre). |
| Bredde (px) / Høyde (px) | Størrelsen på modalen. Sidepanelet bruker hele høyden. |
| Lukkeknapp | Viser × i hjørnet. |
| Klikk utenfor lukker / Esc lukker | De to vanlige utgangene. |
| Oppdater skjermen bak ved lukking | Ved lukking leser datastorene på skjermen som kalte den, på nytt. |
Hintet i selve seksjonen oppsummerer: Åpnes OPPÅ skjermen som kaller den
(Link, hendelser eller keplin.ui.openModal). Utelatt fra direkte
navigasjon.
Åpne og lukke med kode
const resultado = await keplin.ui.openModal("/nova-conta", { setor: "banca" });
if (resultado) {
keplin.data.store("contas").reload();
}
openModalmottar ruten (eller id-en) til skjermen og, valgfritt, parameterne.- Løftet løses først når modalen lukkes, og bringer verdien modalen ga tilbake.
- Inne i modalen lukker
keplin.ui.closeModal(verdi)og gir tilbake den verdien. - Modaler stables: en modal kan åpne en annen.
Nota
keplin.nav.go("/rute") mot en skjerm konfigurert som Modal
(midtstilt) eller Sidepanel (høyre) åpner den som modal i
stedet for å navigere. Det er med vilje: en modal skjerm har ingen egen
adresse i navigasjonen.
Oppskrifter
Lagre og gå tilbake (onClick på Guardar-knappen på Ficha de Conta):
const ok = await keplin.data.store("conta").save();
if (ok) {
keplin.ui.toast("Conta guardada");
keplin.nav.go("/contas");
}
Åpne kortet til den klikkede raden (onRowClick på en Tabell):
keplin.nav.go(`/ficha-de-conta/${keplin.event.row["id"]}`);
Filtrere en tabell med et tekstfelt (onChange på feltet — bytt ut
id-ene med dem fra din egen skjerm):
const texto = keplin.widgets.get("w_pesquisa").getValue();
keplin.widgets.get("w_cta_tab1").setFilter(texto ? { nome: { contains: texto } } : null);
Bekrefte før en destruktiv handling (onClick på en knapp):
if (!(await keplin.ui.confirm("Apagar esta conta?"))) return;
Skjule en knapp for den som ikke kan (onLoad på skjermen):
if (!keplin.session.can("contas.eliminar")) {
keplin.widgets.get("w_apagar").hide();
}
Hvorfor ikke…?
- Hvorfor får jeg ikke lagret hendelsen? Koden kompilerer ikke. Meldingen er Hendelsen ble ikke lagret: koden lar seg ikke kjøre — rett opp og lagre.
- Hvorfor gir
keplin.widgets.get("...")feil? Id-en finnes ikke på denne skjermen. Sjekk den øverst i inspektøren, med widgeten valgt; og husk at hver enhet er sitt eget tre (se Layouter og design per enhet). - Hvorfor utløstes ikke
onParamsChangeved åpning? Det er med vilje: den utløses bare ved endringer. For oppstarten, brukonLoad. - Hvorfor gir ikke modalen noe tilbake? Enten finnes ikke målskjermen, eller den som bruker appen har ikke tillatelse til å åpne den — i begge tilfeller løses løftet uten verdi. Sjekk ruten og tillatelsene.
- Hvorfor åpnes ikke rapportvinduet? Du satte
openetter enawait. Åpne først. - Hvorfor virker det som hendelsen min ikke kjører? Se i Radar: feilene fra hendelseskoden havner der, med skjerm, widget og hendelse — og Radar tar deg rett til editoren for den hendelsen.