English

データテーブル

リストのシグナルの行を、型の付いた列の下に並べる表です。並べ替え、絞り込み、ページ送り、行の選択をブラウザで行うほか、1 ページずつサーバーに求めることもできます。

実行結果

data_table.rs
use hypersig::{NumberFormat, Page, Signals};
use hypersig_ui::{Column, DataTable, TableState, TableText};
use serde::{Deserialize, Serialize};

#[derive(Signals, Serialize, Deserialize)]
pub struct Payment {
    id: i32,
    email: String,
    amount: f64,
}

#[derive(Signals, Serialize, Deserialize)]
pub struct Ledger {
    payments: Vec<Payment>,
    chosen: Vec<i32>,
    table: TableState,
}

pub fn page() -> Page<Ledger> {
    let payments = [
        ("ken99@example.com", 316.0),
        ("abe45@example.com", 242.0),
        ("monserrat44@example.com", 837.0),
        ("silas22@example.com", 874.0),
        ("carmella@example.com", 721.0),
        ("jason78@example.com", 450.0),
        ("sarah23@example.com", 120.5),
    ]
    .into_iter()
    .zip(1..)
    .map(|((email, amount), id)| Payment {
        id,
        email: email.to_owned(),
        amount,
    })
    .collect();
    let table = DataTable::new(
        "支払い",
        Ledger::table(),
        Ledger::payments(),
        |payment| payment.at(Payment::id()),
    )
    .selectable(Ledger::chosen(), |payment| payment.at(Payment::id()))
    .filter(
        "メールアドレスで絞り込む",
        |payment| payment.at(Payment::email()),
    )
    .paginate(5)
    .text(TableText {
        empty: "該当する行はありません。"
            .to_owned(),
        select_row: "行を選ぶ"
            .to_owned(),
        select_all: "すべての行を選ぶ"
            .to_owned(),
        previous_page: "前のページ"
            .to_owned(),
        next_page: "次のページ"
            .to_owned(),
        expand_row: "行の詳細を表示"
            .to_owned(),
    })
    .sortable_column(
        Column::text(
            "メールアドレス",
            Payment::email(),
        ),
        |payment| payment.at(Payment::email()),
    )
    .sortable_column(
        Column::formatted(
            "金額",
            Payment::amount(),
            NumberFormat::new().digits(2).prefix("$"),
        ),
        |payment| payment.at(Payment::amount()),
    );
    Page::new(
        "支払い",
        Ledger {
            payments,
            chosen: Vec::new(),
            table: TableState::default(),
        },
    )
    .child(table)
}

アクセシビリティ

見出しに scope="col" を付けた <table> です。並べ替えられる列の見出しはボタンを持ち、その列で昇順か降順に並んでいるか、並んでいないかを aria-sort で伝えます。見出しのチェックボックスは role="checkbox" のボタンで、一部の行が選ばれている間は aria-checked が mixed になります。ネイティブのチェックボックスの中間状態はプロパティで、属性からは設定できないためです。

列は行の型のフィールドから作るので、別の構造体のフィールドを渡すとコンパイルエラーになります。sortable_column で並べ替えるキーは数値か文字列に限られます。表は絞り込みの文字列、ページ、並べ替えた列を、ページのシグナルにある TableState のフィールドに持ちます。並べ替えはリストのシグナルそのものの順序を変えます。選択は、選んだ行のキーのリストとしてページの別のシグナルに持つので、行の型に選択用のフィールドは要りません。ServerTable ではページを移っても選択が残ります。

ブラウザは変更のたびに行を数え直し、絞り込みとページ送りを両方使うと、その手間は行数の 2 乗で増えます。数千行のリストには ServerTable を使ってください。絞り込みの欄、並べ替えの見出し、ページのボタンが TableState を書き換えてから、それを引数にアクションを呼びます。アクションは、そのページの行と総数をパッチで返します。並べ替えられる列は #[derive(Segment)] を付けた列挙型をキーに取り、サーバーは TableState::sorting で状態からキーを読み戻します。このサイトにはサーバーがないので下のデモはブラウザだけで動き、examples/ui には DataTable と並べて ServerTable を置いています。

ServerTable の状態を URL に残すには、Option のフィールドを持ち #[derive(Search)] を付けたアプリケーション自身の構造体を、ページのルートのクエリパラメータにします。こうするとクエリ文字列のないアドレスも読み込めます。ページのハンドラはそこから TableState::with_sorting で TableState を作り、アクションは状態が指す URL を Patches::replace_url で答えに付けます。再読み込みしても、共有したリンクを開いても、同じページの行が出ます。TableState そのものをクエリパラメータにしないのは、フィールドが 1 つでも欠けた URL に 400 が返るためです。

キー動作
Spaceフォーカスのあるチェックボックスを切り替えます。見出しのチェックボックスでは、すべての行を選び、すべて選ばれていれば選択を外します。
Enter、Space列の見出しで押すと、その列で行を並べ替えます。行の先頭のボタンで押すと、その行の詳細を開閉します。

API

項目概要
DataTable::newlabel を名前に持ち、rows を key で並べ、状態を state に持つ空の表
columnそれまでに足した列の後ろに column を足します。
sortable_column見出しで行を key の順に並べ替える列 column を、それまでに足した列の後ろに足します。
selectable選んだ行の key を selected に持つチェックボックスの列を先頭に足します。
expandable行の下に details を開閉するボタンの列を先頭に足し、開いている行の key を expanded に持ちます。
filterlabel を名前に持つ欄を足し、text がその欄の文字列を含む行だけを表示します。
paginate一度に size 行を表示し、前と次のページに移るボタンを置きます。
max_height表の高さを height までに抑え、見出しを止めたまま行をスクロールさせます。
Column::text見出しが header で、各行の文字列のフィールド field を表示する列
Column::number見出しが header で、数値のフィールド field を行末に揃えて表示する列
Column::formatted見出しが header で、数値のフィールド field を format の形で表示する列
Column::custom見出しが header で、各行に対して render が返す要素をセルに入れる列
visiblewhen が真の間だけ列を表示します。
TableStateDataTable と ServerTable が持つシグナル。絞り込みの文字列、ページ、並べ替え
TableTextDataTable と ServerTable が表示する言葉と、操作部品に付ける名前
ServerTable::newlabel を名前に持ち、rows を key で並べ、行を取りに load を実行する空の表
ServerTable::sortable_column見出しでサーバーに key での並べ替えを求める列 column を、それまでに足した列の後ろに足します。
ServerTable::selectable選んだ行の key を selected に持つチェックボックスの列を先頭に足します。
ServerTable::filterlabel を名前に持つ欄を足し、サーバーがその文字列で行を絞り込みます。
ServerTable::paginatetotal 行のうち size 行ずつのページを表示し、前と次のページに移るボタンを置きます。
TableState::sortingServerTable が並べ替えている列のキーと、その向き