Skip to content

Commit babf503

Browse files
authored
Merge pull request #74 from SSC-SDE/example/bulk-update
Bulk_Update HTMX example - Adding new directory bulk_update with items required as per standard
2 parents 5ddd31f + 78ac389 commit babf503

File tree

12 files changed

+156
-238
lines changed

12 files changed

+156
-238
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from fasthtml.common import *
2+
from collections import defaultdict
3+
4+
app, rt = fast_app()
5+
6+
default_data = [
7+
{'id': 1, 'name': 'Alice', 'age': 25},
8+
{'id': 2, 'name': 'Bob', 'age': 30},
9+
{'id': 3, 'name': 'Charlie', 'age': 28},
10+
]
11+
12+
data = defaultdict(lambda: [dict(d) for d in default_data])
13+
14+
@rt
15+
def index(session):
16+
# if no id, create one so diff users changes don't conflict
17+
if not session.get('id'): session['id'] = unqid()
18+
19+
# Create a table based on the current users data
20+
rows = []
21+
for item in data[session['id']]:
22+
rows.append(
23+
Tr(Td(str(item['id'])),
24+
Td(Input(value=item['name'], name=f"name{item['id']}", _id=f"name{item['id']}")),
25+
Td(Input(value=str(item['age']), name=f"age{item['id']}", _id=f"age{item['id']}"))))
26+
27+
return Div(
28+
Form(
29+
Table(
30+
Thead(Tr(map(Th, ('ID', 'Name', 'Age')))),
31+
Tbody(*rows)),
32+
# Bulk update button that submits all inputs from the table because it's inside fot form.
33+
Button('Bulk Update', hx_post="update", hx_target='#response', hx_indicator="#loading", _type="button", hx_vals={'id': session['id']})),
34+
35+
# Response div that will be updated with the result of the bulk update
36+
Div(id='response'),
37+
# Loading indicator that will be shown when the bulk update is happening
38+
Div(id="loading", style="display:none;", _class="loader"))
39+
40+
@rt
41+
async def update(request, id:str):
42+
changes = []
43+
form_data = await request.form()
44+
45+
# Iterate over the items in the users data
46+
for item in data[id]:
47+
# Get the new name and age from the form data
48+
new_name = form_data.get(f"name{item['id']}")
49+
new_age = form_data.get(f"age{item['id']}")
50+
51+
# Check if the item has changed and if so add it to the changes list
52+
if new_name != item['name'] or new_age != str(item['age']):
53+
changes.append(f"Row {item['id']} changed: Name {item['name']}{new_name}, Age {item['age']}{new_age}")
54+
item['name'] = new_name
55+
item['age'] = int(new_age)
56+
57+
# Return the changes or a message if there are no changes
58+
return Div(*[Div(change) for change in changes]) if changes else Div("No changes detected")
59+
60+
serve()
Loading
Loading
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Bulk Data Update with Fasthtml and HTMX
2+
3+
This example demonstrates how to create a simple web application using Fasthtml and HTMX that allows users to bulk update data displayed in an HTML table. Users can modify the values in the table's input fields and then click a button to submit all the changes at once.
4+
5+
## Key Features
6+
7+
* **Dynamic Table Generation:** The HTML table is dynamically generated from a Python list of dictionaries. Each dictionary represents a row in the table.
8+
* **Client-Side Updates (with HTMX):** The changes are submitted via an AJAX-like request using HTMX. This avoids a full page reload, providing a smoother user experience.
9+
* **Server-Side Processing:** The updates are processed on the server using a Python function.
10+
* **Data Persistence (In-Memory):** The example uses an in-memory data structure (a list of dictionaries) to store the data. In a real-world application, you would replace this with a database or other persistent storage.
11+
* **Preventing Accidental Submissions:** The "Bulk Update" button uses `_type="button"` to prevent the form from being submitted when the user presses Enter in the input fields. This ensures that only a button click triggers the update process.
12+
13+
## How it Works
14+
15+
1. **Data Initialization:** The `data` list of dictionaries holds the initial data for the table.
16+
17+
2. **`index` Route (Table Display):**
18+
- The `index` route function generates the HTML for the table.
19+
- It iterates through the `data` list and creates table rows (`<tr>`) with cells (`<td>`).
20+
- Each cell in the 'Name' and 'Age' columns contains an `<input>` element, allowing the user to edit the values.
21+
- The table is wrapped in a `<form>` element.
22+
- A "Bulk Update" button is included in the form. The `hx_post` attribute on the button specifies the route (`/update`) that will handle the form submission. The `hx_target` attribute specifies where the response from the server should be displayed (`#response`). `hx_indicator` shows a loading indicator while the request is in progress. `_type="button"` prevents form submission on Enter key press.
23+
24+
3. **`/update` Route (Data Processing):**
25+
- The `update` route function handles the POST request when the "Bulk Update" button is clicked.
26+
- It retrieves the form data using `await request.form()`.
27+
- It iterates through the `data` list and compares the new values from the form with the original values.
28+
- If a value has changed, it updates the `data` list and adds a message to the `changes` list.
29+
- Finally, it returns a `Div` containing the messages about the changes.
30+
31+
## How to Use
32+
33+
1. Run the example.
34+
2. The table will be displayed in your browser.
35+
3. Edit the 'Name' and 'Age' values in the input fields as needed.
36+
4. Click the "Bulk Update" button.
37+
5. The changes will be processed, and a message will appear below the button indicating which rows were updated.
38+
39+
## Code Explanation (Key Parts)
40+
41+
```python
42+
@rt # Root route
43+
def index():
44+
# ... (code to generate the table HTML)
45+
return Div(
46+
Form(
47+
Table( #... ),
48+
Button('Bulk Update', hx_post="update", hx_target='#response', hx_indicator="#loading", _type="button")
49+
),
50+
Div(id='response'), # Target for the server response
51+
Div(id="loading", style="display:none;", _class="loader"), # Loading indicator
52+
)
53+
54+
@rt("update", methods=["POST"])
55+
async def update(request):
56+
# ... (code to process the form data and update the data list)
57+
return Div(*[Div(change) for change in changes]) if changes else Div("No changes detected")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[REQUIRED]
2+
ImageAltText=Bulk-Update
3+
ComponentName=Bulk-Update
4+
ComponentDescription=Demonstrates bulk updating of table data.
5+
author = Shankhya
6+
tags = forms, tables, data

examples/dynamic_user_interface_(htmx)/configurable_select/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def mk_form(add_option:str=None, options:str='isaac,hamel,curtis'):
1717
LabelInput("Add an Option", id="add_option"),
1818
Button("Add"),
1919
# fh-frankenui select allows for search boxes
20-
UkSelect(map(Option, opts), searchable=True),
20+
Select(map(Option, opts), searchable=True),
2121
# When the "Add" button is pressed, make a new form
2222
get=mk_form,
2323
# Store options state in DOM

examples/todo_series/_kanban/app.py

Lines changed: 0 additions & 137 deletions
This file was deleted.
-73.7 KB
Binary file not shown.
-91.8 KB
Binary file not shown.

examples/todo_series/_kanban/info.md

Lines changed: 0 additions & 49 deletions
This file was deleted.

examples/todo_series/_kanban/metadata.ini

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)