End-to-end example of building forms with PureAdmin components wired through Phoenix
LiveView's to_form and simple_form. Submissions land in a
per-session ETS cache (Demo.FormCache) with a sliding 30-minute TTL, and
the table below renders them with editing, toast-based undo on delete, and relative
timestamps via PureAdmin.DateTime.
Things to try:
- Submit valid data — the form resets and a success flash replaces any prior status.
- Tick Force validation errors before saving — typed values stick and every
field shows an inline error via the
field={@form[:x]}binding. - Click the pencil to edit a row inline; the submit button switches to Update Entry.
- Click × to delete — the entry disappears and a toast with an Undo action appears.
- Refresh the page — entries (seeded or submitted) survive. Clear All and refresh again to re-seed the defaults.
New Entry
Stored Submissions
3 total
| Name | Department | Start Date | Bio | Submitted | ||
|---|---|---|---|---|---|---|
|
|
Dale Cooper | dale.cooper@twinpeaks.example | Support | 2024-02-24 | Damn fine coffee enthusiast. FBI-level attention to detail. | a minute ago |
|
|
Audrey Horne | audrey.horne@twinpeaks.example | Sales | 2023-09-12 | Great Northern hospitality brought to enterprise accounts. | 5 hours ago |
|
|
Donna Hayward | donna.hayward@twinpeaks.example | Marketing | 2025-01-07 | — | 3 days ago |
How it works
Form binding
-
<.simple_form for={@form}>wraps a Phoenix form; every input usesfield={@form[:x]}to derivename,id,value, and error state automatically. -
Validation returns
[{field, {msg, opts}}, ...];to_form(params, errors: errors)attaches them to the form struct and the input components render the inline error text themselves — no per-fieldform_helpboilerplate in the template. -
Clearing the form after a successful submit uses
push_event("reset-form", %{id: ...})plus a tiny listener inapp.js— LiveView preserves typed values across submits on purpose so errors don't wipe input, so clearing is an explicit opt-in.
State & UX
-
Per-browser session id is planted in the cookie by
DemoWeb.SessionPlug.Demo.FormCachestores submissions in a named ETS table keyed by that id, with a sliding 30-minute TTL and a minute-interval sweeper (Demo.FormCache.Sweeper) that evicts inactive rows. -
Flash banners above the form use
push_flash(..., replace: true)so the next result wipes the previous one instead of stacking. -
Delete uses the optimistic toast + undo pattern
(
push_toastwithactions:). The destructive bulk action (Clear All) uses<.popconfirm>because there's no undo. -
The Submitted column uses
PureAdmin.DateTime.relative/2(localisable via thepureAdmin.datetime.*translation keys); the full timestamp is in the cell'stitletooltip.