3.0 KiB
3.0 KiB
tutorials/02-data-tables.md
# 02 — Data Tables: Storing Greetings Like a Responsible Adult
**Goal:** Save each greeting into Anvil’s built-in database (Data Tables) and show them in a list.
---
## 1. What You’ll Build
- TextBox + Button → Server
- Server saves greeting in a table
- Client displays all saved greetings in a table view (RepeatingPanel)
---
## 2. Set Up Data Tables
1. In your Anvil app → **Data Tables** (left sidebar) → **+ Add Table**
- Name: `greetings`
- Columns:
- `name` (Text)
- `message` (Text)
- `ts` (Datetime, Default: `now()`)
2. Click **Publish Changes**.
---
## 3. Server-Side Code
Edit `ServerModule1`:
```python
from anvil import tables as t, tables
import anvil.server
from datetime import datetime
@anvil.server.callable
def save_greeting(name, message):
"""Saves a greeting into the Data Table."""
tables.app_tables.greetings.add_row(
name=name,
message=message,
ts=datetime.now()
)
return f"Greeting saved for {name} at {datetime.now().strftime('%H:%M:%S')}"
@anvil.server.callable
def get_greetings():
"""Returns all greetings, newest first."""
return tables.app_tables.greetings.search(
tables.order_by("ts", ascending=False)
)
4. Client-Side Code
Modify Form1
from Tutorial 01:
a) Add a RepeatingPanel
- Drag a RepeatingPanel onto
Form1
(ID:repeating_panel_1
). - Bind its
items
property in code.
b) Update Button Click
def button_1_click(self, **event_args):
self.button_1.enabled = False
try:
name = self.text_box_1.text or "World"
message = anvil.server.call('hello_server', name)
Notification(message, timeout=2).show()
# Save greeting
save_status = anvil.server.call('save_greeting', name, message)
print("[Client] Save status:", save_status)
# Refresh list
self.refresh_greetings()
finally:
self.button_1.enabled = True
def refresh_greetings(self):
greetings = anvil.server.call('get_greetings')
self.repeating_panel_1.items = greetings
5. Create a Row Template for RepeatingPanel
-
Double-click the RepeatingPanel → Create FormTemplate1.
-
Add three Labels:
label_name
→ Bind text:self.item['name']
label_message
→ Bind text:self.item['message']
label_ts
→ Bind text:self.item['ts']
-
Style it so it doesn’t look like a 90s spreadsheet.
6. Bonus Challenge (Optional)
- Add a “Clear All” button (server function to delete all rows).
- Add pagination (limit query results, add “Load More” button).
- Highlight greetings from the last minute in green.
7. Assets
- GIF: Show saving multiple greetings and the list updating.
- Save as
/assets/data-tables-demo.gif
- Reference here:

8. Takeaways
- Data Tables are like SQLite without the SQLite drama.
- Always validate server inputs before saving.
- Query ordering matters — newest first keeps users happy.