Skip to main content

yew_datatable/components/
data_table.rs

1//! Main DataTable component.
2
3use crate::components::pagination::Pagination;
4use crate::components::table_body::TableBody;
5use crate::components::table_header::TableHeader;
6use crate::hooks::use_table::UseTableHandle;
7use yew::prelude::*;
8
9/// Props for the DataTable component.
10///
11/// This component accepts a pre-created table handle from the `use_table` hook.
12/// For usage, create the table handle in your component and pass it here.
13#[derive(Properties, Clone)]
14pub struct DataTableProps<T: Clone + PartialEq + 'static> {
15    /// The table handle from use_table hook.
16    pub table: UseTableHandle<T>,
17
18    /// Custom class for the table container.
19    #[prop_or_default]
20    pub class: Classes,
21
22    /// Custom class for the table element.
23    #[prop_or_default]
24    pub table_class: Classes,
25
26    /// Whether to show pagination.
27    #[prop_or(true)]
28    pub show_pagination: bool,
29
30    /// Whether to show global filter.
31    #[prop_or(true)]
32    pub show_global_filter: bool,
33
34    /// Placeholder for global filter input.
35    #[prop_or_else(|| "Search...".to_string())]
36    pub filter_placeholder: String,
37
38    /// Whether rows are selectable.
39    #[prop_or(true)]
40    pub selectable: bool,
41}
42
43/// Compares `DataTableProps` by all fields, including the table handle.
44impl<T: Clone + PartialEq + 'static> PartialEq for DataTableProps<T> {
45    fn eq(&self, other: &Self) -> bool {
46        // Compare the table handle for reactivity-aware equality.
47        self.table == other.table
48            // Compare all configuration fields.
49            && self.class == other.class
50            && self.table_class == other.table_class
51            && self.show_pagination == other.show_pagination
52            && self.show_global_filter == other.show_global_filter
53            && self.filter_placeholder == other.filter_placeholder
54            && self.selectable == other.selectable
55    }
56}
57
58/// A complete data table component with all features.
59///
60/// Use this component with a table handle created by the `use_table` hook:
61///
62/// ```ignore
63/// let table = use_table(columns, data, None);
64/// html! { <DataTable<MyRow> table={table} /> }
65/// ```
66#[function_component(DataTable)]
67pub fn data_table<T: Clone + PartialEq + 'static>(props: &DataTableProps<T>) -> Html {
68    // Clone the table handle for use in callbacks.
69    let table = props.table.clone();
70
71    // Create the global filter input callback.
72    let on_global_filter = {
73        let table = table.clone();
74        Callback::from(move |e: InputEvent| {
75            // Extract the input element from the event target.
76            let target = e.target_dyn_into::<web_sys::HtmlInputElement>();
77            if let Some(input) = target {
78                // Apply the filter value to the table.
79                table.set_global_filter(input.value());
80            }
81        })
82    };
83
84    html! {
85        <div class={classes!("datatable-container", props.class.clone())}>
86            {if props.show_global_filter {
87                html! {
88                    <div class="datatable-toolbar">
89                        <input
90                            type="text"
91                            class="global-filter"
92                            placeholder={props.filter_placeholder.clone()}
93                            oninput={on_global_filter}
94                        />
95                    </div>
96                }
97            } else {
98                html! {}
99            }}
100
101            <table class={classes!("datatable", props.table_class.clone())}>
102                <TableHeader<T> table={table.clone()} />
103                <TableBody<T> table={table.clone()} selectable={props.selectable} />
104            </table>
105
106            {if props.show_pagination {
107                html! {
108                    <Pagination<T> table={table.clone()} />
109                }
110            } else {
111                html! {}
112            }}
113        </div>
114    }
115}