ModelGrid¶
examples/05_grid.py · run it with uv run python examples/05_grid.py

Three variants of the AgGrid-based table component:
- ModelGrid — read-only display of a list
- ModelGridInlineEdit — per-cell editing with immediate validation and persistence; backed by an in-memory list here
- ModelGridInlineEdit (JSON) — same as above, but persists to a JSON file automatically after every change; the file is created on first run
Source
"""
# ModelGrid
Three variants of the AgGrid-based table component:
- **ModelGrid** — read-only display of a list
- **ModelGridInlineEdit** — per-cell editing with immediate validation and
persistence; backed by an in-memory list here
- **ModelGridInlineEdit (JSON)** — same as above, but persists to a JSON file
automatically after every change; the file is created on first run
"""
from pathlib import Path
import pydantic
from typing import Annotated, Literal
from nicegui import ui
import niceview
from niceview import ModelGrid, ModelGridInlineEdit
# Stored ids -> display labels. The grid shows the label, stores the id, and (inline) edits
# through a dropdown of these labels.
PRIORITY_LABELS = {'low': 'Low', 'medium': 'Medium', 'high': 'High'}
class Task(pydantic.BaseModel):
title: str = pydantic.Field(default='', max_length=40, title='Title')
priority: Annotated[
Literal['low', 'medium', 'high'],
pydantic.Field(title='Priority'),
niceview.Field(widget_type='ui.select', options=PRIORITY_LABELS),
] = 'medium'
done: bool = pydantic.Field(default=False, title='Done')
TASKS_PATH = Path('./example_tasks.json')
tasks = [
Task(title='Buy groceries', priority='low', done=True),
Task(title='Write report', priority='high', done=False),
Task(title='Call dentist', priority='medium', done=False),
Task(title='Fix bug #42', priority='high', done=False),
Task(title='Review PR', priority='medium', done=True),
]
@ui.page('/')
def page():
ui.markdown(__doc__ or '')
ui.separator()
with ui.card().classes('w-full'):
ui.label('ModelGrid — read-only').classes('text-h6')
ModelGrid.from_list(Task, tasks).render().widget.classes('w-full')
with ui.card().classes('w-full'):
ui.label('ModelGridInlineEdit — in-memory').classes('text-h6')
ui.label('Double-click a cell to edit it. Changes are persisted in memory only.').classes('text-small')
grid = ModelGridInlineEdit.from_list(Task, tasks)
grid.render().widget.classes('w-full')
grid.on_change(lambda e: ui.notify(f'{e.field_name} → {e.new_value}'))
with ui.card().classes('w-full'):
ui.label(f'ModelGridInlineEdit — JSON file ({TASKS_PATH})').classes('text-h6')
ModelGridInlineEdit.from_json(Task, TASKS_PATH).render().widget.classes('w-full')
ui.run(title='05 — ModelGrid')