Skip to content

Commit f5bed80

Browse files
authored
Merge pull request #75 from CarloLepelaars/main
Active Search
2 parents 633e439 + 42767dd commit f5bed80

File tree

6 files changed

+97
-0
lines changed

6 files changed

+97
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from fasthtml.common import *
2+
3+
app, rt = fast_app()
4+
5+
# Example contacts data
6+
contacts = [
7+
{"first_name": "Venus", "last_name": "Grimes", "email": "[email protected]"},
8+
{"first_name": "Fletcher", "last_name": "Owen", "email": "[email protected]"},
9+
{"first_name": "William", "last_name": "Hale", "email": "[email protected]"},
10+
{"first_name": "TaShya", "last_name": "Cash", "email": "[email protected]"},
11+
{"first_name": "Kevyn", "last_name": "Hoover", "email": "[email protected]"},
12+
{"first_name": "Jakeem", "last_name": "Walker", "email": "[email protected]"},
13+
{"first_name": "Malcolm", "last_name": "Trujillo", "email": "[email protected]"},
14+
{"first_name": "Wynne", "last_name": "Rice", "email": "[email protected]"},
15+
{"first_name": "Evangeline", "last_name": "Klein", "email": "[email protected]"},
16+
{"first_name": "Jennifer", "last_name": "Russell", "email": "[email protected]"},
17+
{"first_name": "Rama", "last_name": "Freeman", "email": "[email protected]"},
18+
{"first_name": "Jena", "last_name": "Mathis", "email": "[email protected]"},
19+
{"first_name": "Alexandra", "last_name": "Maynard", "email": "[email protected]"},
20+
{"first_name": "Tallulah", "last_name": "Haley", "email": "[email protected]"},
21+
{"first_name": "Timon", "last_name": "Small", "email": "[email protected]"},
22+
]
23+
24+
# Mapping of keys to clean labels
25+
mapping = {
26+
"first_name": "First Name",
27+
"last_name": "Last Name",
28+
"email": "Email"
29+
}
30+
keys = list(mapping)
31+
32+
def show_contacts(contacts: list[dict]):
33+
# HTML rows for all given contacts
34+
return [Tr(*[Td(contact[col]) for col in keys]) for contact in contacts]
35+
36+
# POST request to handle search
37+
@rt("/search")
38+
def post(search: str = None):
39+
# Default search term is empty string, which shows all contacts
40+
# If a search term is provided, it is converted to lowercase
41+
search_term = search.lower() if search else ""
42+
# Filter contacts based on search term
43+
# Uses First Name, Last Name, and Email to search
44+
filtered_contacts = [
45+
contact for contact in contacts
46+
if any(search_term in str(contact[key]).lower() for key in keys)
47+
]
48+
# Get HTML for each row in the filtered contacts
49+
return show_contacts(filtered_contacts)
50+
51+
@rt
52+
def index():
53+
return Titled("Active Search",
54+
Div(
55+
56+
H3("Search Contacts"),
57+
# HTMX for searching contacts
58+
Input(
59+
type="search",
60+
name="search",
61+
# Default shown in search bar
62+
placeholder="Begin Typing To Search Users...",
63+
# Input is of a form type
64+
class_="form-control",
65+
# A POST request to '/search' is called when the user types
66+
hx_post="/search",
67+
# Search is delayed by 500ms to delay the search until the user has stopped typing
68+
# 'changed' is to ensure that no new search are triggered when the
69+
# user doesn't change the input of pastes the same value.
70+
# 'keyup[key=='Enter']' triggers the search once enter is pressed.
71+
# 'load' is to show all results initially on the page load.
72+
hx_trigger="input changed delay:500ms, keyup[key=='Enter'], load",
73+
# Put results in the search-results div
74+
hx_target="#search-results",
75+
),
76+
# The table initially shows all contacts and
77+
# dynamically updates when the user types in the search bar.
78+
Table(
79+
Thead(
80+
Tr(*[Th(mapping[key]) for key in keys])
81+
),
82+
Tbody(*show_contacts(contacts), id="search-results"),
83+
class_="table"
84+
),
85+
class_="container"
86+
)
87+
)
88+
89+
serve()
Loading
Loading
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[REQUIRED]
2+
ImageAltText=Active search over a table
3+
ComponentName=Active Search
4+
ComponentDescription=A search bar that updates a table as the user types.

llms.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Tic Tac Toe(https://github.com/AnswerDotAI/fasthtml-gallery/blob/main/examples/applications/tic_tac_toe/app.py)
1111

1212
## Dynamic User Interface (Htmx)
13+
- Active Search(https://github.com/AnswerDotAI/fasthtml-gallery/blob/main/examples/dynamic_user_interface_(htmx)/active_search/app.py)
1314
- Animations(https://github.com/AnswerDotAI/fasthtml-gallery/blob/main/examples/dynamic_user_interface_(htmx)/animations/app.py)
1415
- Bulk Update(https://github.com/AnswerDotAI/fasthtml-gallery/blob/main/examples/dynamic_user_interface_(htmx)/bulk_update/app.py)
1516
- Cascading Dropdowns(https://github.com/AnswerDotAI/fasthtml-gallery/blob/main/examples/dynamic_user_interface_(htmx)/cascading_dropdowns/app.py)

llms_ctx.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,9 @@ def homepage():
493493
</example>
494494
</category>
495495
<category name="Dynamic User Interface (Htmx)">
496+
<example name="Active Search">
497+
404: Not Found
498+
</example>
496499
<example name="Animations">
497500
import random
498501
from fasthtml.common import *

0 commit comments

Comments
 (0)