pub struct DataTable<S, T> { /* private fields */ }Expand description
A table of the rows of a list signal, sorted, filtered, and paged in the browser.
Each row is keyed by key, as in
each_keyed, so a row keeps its element,
and its checkbox its focus, when sorting moves it. Everything the table
does runs in the browser on the list signal and the TableState:
- A column added with
DataTable::sortable_columnhas a button in its header that sorts the rows, and the header’saria-sortsays which way. DataTable::filteradds a text field and shows the rows whose text contains what the visitor types, ignoring case.DataTable::paginateshows a fixed number of the rows that pass the filter, with buttons for the previous and the next page.DataTable::selectableadds a column of checkboxes that keep the keys of the selected rows in a list signal, under a header checkbox that selects or clears all of them. The header follows the WAI-ARIA checkbox pattern witharia-checked="mixed"while some rows are selected.
A page past the last row, which the list reaches by shrinking from outside the table, returns the table to its first page.
The header checkbox selects every row of the list, including rows the
filter or the page hides. A selected key stays in the list after its
row leaves the table, until the header clears the selection or the
page removes the key. Rows are counted on each change of the list,
the filter, or the page, and the work grows with the square of the
number of rows while a filter and pagination are both on, so a list of
thousands of rows belongs in a ServerTable, which receives one page
at a time from the server.
use hypersig::{Page, Signals};
use hypersig_ui::{Column, DataTable, TableState};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
struct User {
id: i32,
email: String,
}
#[derive(Signals, Serialize, Deserialize)]
struct Users {
users: Vec<User>,
chosen: Vec<i32>,
table: TableState,
}
let table = DataTable::new("Users", Users::table(), Users::users(), |user| user.at(User::id()))
.selectable(Users::chosen(), |user| user.at(User::id()))
.filter("Filter emails", |user| user.at(User::email()))
.paginate(10)
.sortable_column(Column::text("Email", User::email()), |user| user.at(User::email()))
.column(Column::number("Id", User::id()));
let users = vec![User { id: 1, email: "ada@example.com".into() }];
let html = Page::new("Users", Users { users, chosen: vec![1], table: TableState::default() })
.child(table)
.render();
assert!(html.contains(r#"aria-sort="none""#));
assert!(html.contains(r#"aria-checked="true""#));Implementations§
Source§impl<S: 'static, T: 'static> DataTable<S, T>
impl<S: 'static, T: 'static> DataTable<S, T>
Sourcepub fn new<K: 'static, E: IntoExpr<S, K>>(
label: impl Into<String>,
state: Sig<S, TableState>,
rows: Sig<S, Vec<T>>,
key: impl FnOnce(Item<S, T>) -> E + 'static,
) -> Self
pub fn new<K: 'static, E: IntoExpr<S, K>>( label: impl Into<String>, state: Sig<S, TableState>, rows: Sig<S, Vec<T>>, key: impl FnOnce(Item<S, T>) -> E + 'static, ) -> Self
An empty table named label, listing rows by key, with its state in state.
The name is for assistive technology, and the table has no columns
until DataTable::column adds them.
Sourcepub fn sortable_column<K: Comparable, E: IntoExpr<S, K>>(
self,
column: Column<S, T>,
key: impl Fn(Item<S, T>) -> E + 'static,
) -> Self
pub fn sortable_column<K: Comparable, E: IntoExpr<S, K>>( self, column: Column<S, T>, key: impl Fn(Item<S, T>) -> E + 'static, ) -> Self
Adds column, whose header sorts the rows by key, after the columns added so far.
The compiler requires the key to be a number or a string, because the runtime orders only those. The first press on the header sorts the rows ascending, and a press on a column sorted ascending sorts it descending. Sorting reorders the list signal itself and keeps the order of rows with equal keys, so sorting by one column and then by another orders the rows by the second and then the first. The order holds until the list changes. A list the server patches afterwards arrives in the server’s order, while the header still marks the last sort.
Sourcepub fn selectable<K: PartialEq + 'static, E: IntoExpr<S, K>>(
self,
selected: Sig<S, Vec<K>>,
key: impl Fn(Item<S, T>) -> E + 'static,
) -> Self
pub fn selectable<K: PartialEq + 'static, E: IntoExpr<S, K>>( self, selected: Sig<S, Vec<K>>, key: impl Fn(Item<S, T>) -> E + 'static, ) -> Self
Adds a first column of checkboxes that keep the key of each selected row in selected.
The keys live in a signal of the page, apart from the rows, so a
selection needs no field in the row type and outlasts a patch of the
rows. The keys are compared as JSON, as each_keyed compares them.
Sourcepub fn expandable<K: PartialEq + 'static, E: IntoExpr<S, K>>(
self,
expanded: Sig<S, Vec<K>>,
key: impl Fn(Item<S, T>) -> E + 'static,
details: impl Fn(Item<S, T>) -> El<S> + 'static,
) -> Self
pub fn expandable<K: PartialEq + 'static, E: IntoExpr<S, K>>( self, expanded: Sig<S, Vec<K>>, key: impl Fn(Item<S, T>) -> E + 'static, details: impl Fn(Item<S, T>) -> El<S> + 'static, ) -> Self
Adds a first column of buttons that show details of a row under it, keeping the key of each open row in expanded.
The button carries aria-expanded, as the WAI-ARIA disclosure
pattern asks, and the details fill a row of their own under the row,
across every column. Each row and its details are a <tbody> of
their own, so the two move together when the rows are sorted.
Sourcepub fn filter<E: IntoExpr<S, String>>(
self,
label: impl Into<String>,
text: impl Fn(Item<S, T>) -> E + 'static,
) -> Self
pub fn filter<E: IntoExpr<S, String>>( self, label: impl Into<String>, text: impl Fn(Item<S, T>) -> E + 'static, ) -> Self
Adds a field named label that shows the rows whose text contains its text.
The field sits above the table. The match ignores case, and typing returns the table to its first page.
Sourcepub fn paginate(self, size: i32) -> Self
pub fn paginate(self, size: i32) -> Self
Shows size rows at a time, with buttons for the previous and next page.
Below the table, the range of rows shown is written as 1–5 / 12.
§Panics
Panics if size is less than 1.
Sourcepub fn text(self, text: TableText) -> Self
pub fn text(self, text: TableText) -> Self
Replaces the words the table shows and names its controls with, English until set.
Sourcepub fn max_height(self, height: Length) -> Self
pub fn max_height(self, height: Length) -> Self
Keeps the table at most height high, scrolling its rows under a header that stays in place.