Search as you type
Task: a search field over books that updates the list while you type, and still works without JavaScript.
yaml
# Recipe: a search field that refreshes the results while you type.
paths:
components: ./components
migrations: ./migrations
datasources:
db:
driver: sqlite
database: ./data/library.dbsql
CREATE TABLE books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL
);
INSERT INTO books (title, author) VALUES
('Dom Casmurro', 'Machado de Assis'),
('Quincas Borba', 'Machado de Assis'),
('Vidas Secas', 'Graciliano Ramos'),
('Grande Sertão: Veredas', 'João Guimarães Rosa');The search is a GET parameter (?q=), read by the page's own query. search="results" on the field asks for the same page after each pause in typing and swaps only the element with id="results"; the URL follows, so the result can be shared or reloaded.
xml
<q:component name="Library">
<!-- The search is the URL's ?q=; the page's own query does the searching. -->
<q:set name="term" value="{query.q}" default="" />
<q:query name="found" datasource="db">
SELECT title, author FROM books
WHERE title LIKE :pattern OR author LIKE :pattern
ORDER BY title
<q:param name="pattern" value="%{term}%" type="string" />
</q:query>
<ui:window title="Library">
<!-- search="results": after a pause in typing, the page is asked again
with ?q=… and only #results is swapped. Enter works without JavaScript. -->
<ui:input bind="q" value="{term}" search="results" placeholder="Title or author" />
<ui:vbox id="results">
<ui:text>{found_result.recordCount} books</ui:text>
<ui:list source="{found}" as="b">
<ui:item><ui:text>{b.title} — {b.author}</ui:text></ui:item>
</ui:list>
</ui:vbox>
</ui:window>
</q:component>xml
<q:test name="every book before a search" page="/">
<test:visit />
<test:expect text="4 books" />
</q:test>
<q:test name="a title or an author" page="/">
<test:visit q="machado" />
<test:expect text="2 books" />
<test:expect text="Quincas Borba — Machado de Assis" />
<test:expect no-text="Vidas Secas" />
</q:test>
<q:test name="nothing found" page="/">
<test:visit q="tolstoy" />
<test:expect text="0 books" />
</q:test>text
tests/search.test.q
PASS every book before a search
PASS a title or an author
PASS nothing found
3 passed, 0 failedSee UI-12.