Skip to content

ModelGrid

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

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
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')