---
title: "State-Bag in einem Textfeld"
slug: "tips_statefield"
category: "Templates"
hosts: "ninox"
description: "Ein JSON-Textfeld als UI-State in Ninox — Tabs, Filter, ausgewählte IDs ohne Extra-Hilfsfelder."
---

Hey zusammen! 👋

Ich habe kürzlich immer mehr mit sogenannten **StateFields** gearbeitet und wollte das Konzept mal teilen – vielleicht hilft es euch auch weiter.

**Das Problem:**
Für jeden Filter, Tab oder ausgewählten Datensatz braucht man normalerweise ein eigenes Ninox-Feld. Bei komplexeren UIs hat man schnell 5–10 Helper-Felder im Schema, nur für UI-Zustände.

**Die Lösung: Ein JSON-Feld als „State-Bag"**
Ein einziges Textfeld speichert ein JSON-Objekt mit beliebig vielen Keys. Navigation, Filter, ausgewählte IDs – alles in einem Feld.

---

**1. Feld und Rohdaten auslesen**

```
let stateField := fieldId(Nr, "helper_uiState");
let stateRaw := if current.helper_uiState then
    parseJSON(text(current.helper_uiState))
else
    {}
end;
```

**2. Einzelne Werte extrahieren (mit Default-Werten)**

```
let activeTab := if item(stateRaw, "activeTab") then
    text(item(stateRaw, "activeTab"))
else
    "uebersicht"
end;

let statusFilter := if item(stateRaw, "statusFilter") then
    text(item(stateRaw, "statusFilter"))
else
    "alle"
end;

let selectedRecordId := if item(stateRaw, "selectedId") then
    text(item(stateRaw, "selectedId"))
else
    ""
end;
```

**3. Werte schreiben — empfohlen: `dataBag` auf der Action**

Partielles Patchen ohne manuelles `setItem` in der Formel — der Action Performer übernimmt Read → Patch → Write:

```
{
    type: "update",
    recordId: Nr,
    fieldId: stateField,
    dataBag: {
        base: helper_uiState,
        patch: { activeTab: "details" }
    }
}
```

Ausführlich: [`data-bag-actions`](../patterns/data-bag-actions.md) — gilt für **alle Widgets mit `actions`** (Button, Layout, Table, Drawing, …).

**Alternative (manuell):** Topf lesen → `setItem` → `formatJSON` als `value`:

```
let uiData := parseJSON(
    if current.helper_uiState then
        text(current.helper_uiState)
    else
        "{}"
    end);
setItem(uiData, "activeTab", "details");
```

Dann als Action:

```
{
    type: "update",
    recordId: Nr,
    field: stateField,
    value: formatJSON(uiData)
}
```

**4. Mehrere Keys gleichzeitig setzen (z.B. Zurück-Button)**

Mit `dataBag` mehrere Keys in einem Patch:

```
dataBag: {
    base: helper_uiState,
    patch: { selectedId: "", statusFilter: "alle" }
}
```

Oder manuell:

```
let uiDataReset := parseJSON(text(current.helper_uiState));
setItem(uiDataReset, "selectedId", "");
setItem(uiDataReset, "statusFilter", "alle");
--- value: formatJSON(uiDataReset) in der Action ---;
```

---

**Genutzte Ninox-Funktionen:**
- `parseJSON()` / `formatJSON()` – JSON ↔ Objekt (Plain-JSON im Textfeld)
- `setItem(obj, "key", value)` – Key setzen
- `item(obj, "key")` – Wert auslesen

**Legacy:** Ältere Projekte nutzen manchmal `urlEncode`/`urlDecode` um JSON in Actions zu schreiben. Für neue Apps: **`dataBag` + Plain-JSON** — siehe [`data-bag-actions`](../patterns/data-bag-actions.md#legacy-urlencoded).

**Vorteile:**
- **Ein Feld statt vieler** – Filter, Tabs, ausgewählte IDs in einem Feld
- **Einfach erweiterbar** – neuer Key = kein neues Feld im Schema
- **Übersichtlich** – alle Keys an einer Stelle dokumentieren
- **Weniger Wartung** – weniger Felder im Formular

**Tipp:** Keys am besten im Code dokumentieren:

```
--- State-Keys: activeTab (uebersicht|details), statusFilter (alle|offen|erledigt), selectedId ---;
```

Viel Spaß damit! 🚀
