Add tutorials/01-hello-fluid-frame.md tutorials/02-data-tables.md
feat(tutorials): add Hello Fluid Frame + Data Tables with persistence, querying, and RepeatingPanel display
This commit is contained in:
parent
23648056b3
commit
64731e833c
|
@ -0,0 +1,135 @@
|
||||||
|
**`tutorials/02-data-tables.md`**
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
# 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
|
||||||
|
|
||||||
|
1. Drag a **RepeatingPanel** onto `Form1` (ID: `repeating_panel_1`).
|
||||||
|
2. Bind its `items` property in code.
|
||||||
|
|
||||||
|
### b) Update Button Click
|
||||||
|
|
||||||
|
```python
|
||||||
|
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
|
||||||
|
|
||||||
|
1. Double-click the RepeatingPanel → Create **FormTemplate1**.
|
||||||
|
2. Add three Labels:
|
||||||
|
|
||||||
|
* `label_name` → Bind text: `self.item['name']`
|
||||||
|
* `label_message` → Bind text: `self.item['message']`
|
||||||
|
* `label_ts` → Bind text: `self.item['ts']`
|
||||||
|
3. 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:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
git add tutorials/01-hello-fluid-frame.md tutorials/02-data-tables.md
|
||||||
|
git commit -m "feat(tutorials): add Hello Fluid Frame + Data Tables with persistence, querying, and RepeatingPanel display"
|
||||||
|
git push origin main
|
||||||
|
````
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If you want, I can also make **Tutorial 03 — Server Modules & Security** a bit more difficult by adding role-based access control so that only logged-in users with a certain role can call a sensitive server function. That would round out the trio. Want me to do that next?
|
Loading…
Reference in New Issue