Summary#
SearchPicker chooses one row of a table too big to list. The text the person types is a field of the page, the
page's query reads it, so each keystroke is answered by the database, over every row — the page never loads the
table to filter it. The match is offered in a panel under the box; picking one sets the value and shows it.
entity Vendor {
[Required, MaxLength(80)] string Name;
security { allow read, create when IsAnonymous || IsAuthenticated; }
}
[Route("/pick")] [Render(CSR)] [AllowAnonymous]
component PickVendor() {
string find = "";
Vendor? vendor = null;
live var matches = Vendor.Where(v => v.Name.Contains(find)).OrderBy(v => v.Name).Take(20).ToList();
render {
Stack(gap: 2, p: 6) {
SearchPicker("Vendor", value: vendor, search: find, options: matches) { v => Text(v.Name); }
if (vendor != null) { Text("Buying from " + vendor.Name); }
}
}
}Signature#
string find = "";
live var matches = Entity.Where(x => x.Name.Contains(find)).OrderBy(x => x.Name).Take(20).ToList();
SearchPicker("…", value: chosen, search: find, options: matches) { x => Text(x.Name); }
// SearchPicker<T>(string label, Binding<T> value, Binding<string> search, T[] options,
// string placeholder = "Type to search", bool disabled = false)Description#
How it behaves#
The panel opens on what was typed, never on an empty box. It lists the page's matches with the template's row, says
"Nothing matches …" when there are none, and — when the page reads with no .Take and more rows match than one
answer carries — "More match — keep typing to narrow it." Picking a row sets value, clears the search and shows
the row; pressing it searches again. Esc clears the search. value is a two-way binding, T? for an optional choice,
as on Dropdown. In a test, fill it by its label and press the match: Ui.Fill("Vendor", "acm"), then
Ui.Click("Acme Ltd").
Dropdown stays the control for an enum, or for a handful of rows the page already holds.
When does the lint fire?#
ui-picker-over-a-growing-entity is a SHOULD finding on a component field read from an entity with no Take whose
rows are handed to a choice control — Dropdown, Select, Combobox, RadioGroup, or any control named …Picker,
SearchPicker included — as its options or written inside it. Past a few dozen nobody finds an option by scrolling,
and past the first answer (about 2 MB of rows, How many rows a page is sent) the rows after it are not offered at all — the one
being looked for is simply missing.
When is it silent?#
When the choices are an enum's members (Dropdown("Status", value: s) over T.Members is not a query), or the
read is bounded: a Take, a one-row read, an aggregate, or a child collection pinned to one parent.
What can it not tell?#
Whether the entity is reference data that never grows — a dozen currencies, the countries. The source does not say.
Write .Take(n) naming its size: it says what the page means and silences the finding.
See also#
- How many rows a page is sent — what a page is sent
- Lists that load more — a list that offers the rest of the rows
- Acting on data — a calm grid header, filters as chips, and a toolbar that follows the selection —
SearchFieldand the grid's own filters