yew_datatable/components/
pagination.rs1use crate::hooks::use_table::UseTableHandle;
4use wasm_bindgen::JsCast;
5use yew::prelude::*;
6
7#[derive(Properties, Clone)]
9pub struct PaginationProps<T: Clone + PartialEq + 'static> {
10 pub table: UseTableHandle<T>,
12
13 #[prop_or_default]
15 pub class: Classes,
16
17 #[prop_or_default]
19 pub button_class: Classes,
20
21 #[prop_or_default]
23 pub disabled_class: Classes,
24
25 #[prop_or(true)]
27 pub show_page_size_selector: bool,
28
29 #[prop_or(true)]
31 pub show_page_info: bool,
32
33 #[prop_or_else(|| vec![10, 20, 30, 50, 100])]
35 pub page_size_options: Vec<usize>,
36}
37
38impl<T: Clone + PartialEq + 'static> PartialEq for PaginationProps<T> {
40 fn eq(&self, other: &Self) -> bool {
41 self.table == other.table
43 && self.class == other.class
45 && self.button_class == other.button_class
46 && self.disabled_class == other.disabled_class
47 && self.show_page_size_selector == other.show_page_size_selector
48 && self.show_page_info == other.show_page_info
49 && self.page_size_options == other.page_size_options
50 }
51}
52
53#[function_component(Pagination)]
55pub fn pagination<T: Clone + PartialEq + 'static>(props: &PaginationProps<T>) -> Html {
56 let current_page = props.table.current_page();
58 let page_count = props.table.page_count();
59 let page_size = props.table.page_size();
60 let total_rows = props.table.filtered_row_count();
61 let can_previous = props.table.can_previous_page();
62 let can_next = props.table.can_next_page();
63
64 let on_first = {
66 let table = props.table.clone();
67 Callback::from(move |_: MouseEvent| {
68 table.go_to_page(0);
69 })
70 };
71
72 let on_previous = {
74 let table = props.table.clone();
75 Callback::from(move |_: MouseEvent| {
76 table.previous_page();
77 })
78 };
79
80 let on_next = {
82 let table = props.table.clone();
83 Callback::from(move |_: MouseEvent| {
84 table.next_page();
85 })
86 };
87
88 let on_last = {
90 let table = props.table.clone();
91 let last_page = page_count.saturating_sub(1);
92 Callback::from(move |_: MouseEvent| {
93 table.go_to_page(last_page);
94 })
95 };
96
97 let on_page_size_change = {
99 let table = props.table.clone();
100 Callback::from(move |e: Event| {
101 if let Some(target) = e.target() {
103 if let Ok(select) = target.dyn_into::<web_sys::HtmlSelectElement>() {
104 let value = select.value();
106 if let Ok(size) = value.parse::<usize>() {
107 table.set_page_size(size);
108 }
109 }
110 }
111 })
112 };
113
114 let button_class = |disabled: bool| {
116 if disabled {
117 classes!(props.button_class.clone(), props.disabled_class.clone())
118 } else {
119 props.button_class.clone()
120 }
121 };
122
123 let start_row = if total_rows == 0 {
125 0
126 } else {
127 current_page * page_size + 1
128 };
129 let end_row = ((current_page + 1) * page_size).min(total_rows);
130
131 html! {
132 <div class={classes!("pagination", props.class.clone())}>
133 {if props.show_page_size_selector {
134 html! {
135 <div class="page-size-selector">
136 <label>{"Show "}</label>
137 <select onchange={on_page_size_change} value={page_size.to_string()}>
138 {props.page_size_options.iter().map(|&size| {
139 html! {
140 <option
141 value={size.to_string()}
142 selected={size == page_size}
143 >
144 {size}
145 </option>
146 }
147 }).collect::<Html>()}
148 </select>
149 <label>{" entries"}</label>
150 </div>
151 }
152 } else {
153 html! {}
154 }}
155
156 <div class="page-navigation">
157 <button
158 class={button_class(!can_previous)}
159 onclick={on_first}
160 disabled={!can_previous}
161 >
162 {"⟪"}
163 </button>
164 <button
165 class={button_class(!can_previous)}
166 onclick={on_previous}
167 disabled={!can_previous}
168 >
169 {"◀"}
170 </button>
171 <span class="page-info-inline">
172 {format!("Page {} of {}", current_page + 1, page_count.max(1))}
173 </span>
174 <button
175 class={button_class(!can_next)}
176 onclick={on_next}
177 disabled={!can_next}
178 >
179 {"▶"}
180 </button>
181 <button
182 class={button_class(!can_next)}
183 onclick={on_last}
184 disabled={!can_next}
185 >
186 {"⟫"}
187 </button>
188 </div>
189
190 {if props.show_page_info {
191 html! {
192 <div class="page-info">
193 {format!("Showing {} to {} of {} entries", start_row, end_row, total_rows)}
194 </div>
195 }
196 } else {
197 html! {}
198 }}
199 </div>
200 }
201}