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.class == other.class
43 && self.button_class == other.button_class
44 && self.disabled_class == other.disabled_class
45 && self.show_page_size_selector == other.show_page_size_selector
46 && self.show_page_info == other.show_page_info
47 && self.page_size_options == other.page_size_options
48 }
49}
50
51#[function_component(Pagination)]
53pub fn pagination<T: Clone + PartialEq + 'static>(props: &PaginationProps<T>) -> Html {
54 let current_page = props.table.current_page();
56 let page_count = props.table.page_count();
57 let page_size = props.table.page_size();
58 let total_rows = props.table.filtered_row_count();
59 let can_previous = props.table.can_previous_page();
60 let can_next = props.table.can_next_page();
61
62 let on_first = {
64 let table = props.table.clone();
65 Callback::from(move |_: MouseEvent| {
66 table.go_to_page(0);
67 })
68 };
69
70 let on_previous = {
72 let table = props.table.clone();
73 Callback::from(move |_: MouseEvent| {
74 table.previous_page();
75 })
76 };
77
78 let on_next = {
80 let table = props.table.clone();
81 Callback::from(move |_: MouseEvent| {
82 table.next_page();
83 })
84 };
85
86 let on_last = {
88 let table = props.table.clone();
89 let last_page = page_count.saturating_sub(1);
90 Callback::from(move |_: MouseEvent| {
91 table.go_to_page(last_page);
92 })
93 };
94
95 let on_page_size_change = {
97 let table = props.table.clone();
98 Callback::from(move |e: Event| {
99 if let Some(target) = e.target() {
101 if let Ok(select) = target.dyn_into::<web_sys::HtmlSelectElement>() {
102 let value = select.value();
104 if let Ok(size) = value.parse::<usize>() {
105 table.set_page_size(size);
106 }
107 }
108 }
109 })
110 };
111
112 let button_class = |disabled: bool| {
114 if disabled {
115 classes!(props.button_class.clone(), props.disabled_class.clone())
116 } else {
117 props.button_class.clone()
118 }
119 };
120
121 let start_row = if total_rows == 0 {
123 0
124 } else {
125 current_page * page_size + 1
126 };
127 let end_row = ((current_page + 1) * page_size).min(total_rows);
128
129 html! {
130 <div class={classes!("pagination", props.class.clone())}>
131 {if props.show_page_size_selector {
132 html! {
133 <div class="page-size-selector">
134 <label>{"Show "}</label>
135 <select onchange={on_page_size_change} value={page_size.to_string()}>
136 {props.page_size_options.iter().map(|&size| {
137 html! {
138 <option
139 value={size.to_string()}
140 selected={size == page_size}
141 >
142 {size}
143 </option>
144 }
145 }).collect::<Html>()}
146 </select>
147 <label>{" entries"}</label>
148 </div>
149 }
150 } else {
151 html! {}
152 }}
153
154 <div class="page-navigation">
155 <button
156 class={button_class(!can_previous)}
157 onclick={on_first}
158 disabled={!can_previous}
159 >
160 {"⟪"}
161 </button>
162 <button
163 class={button_class(!can_previous)}
164 onclick={on_previous}
165 disabled={!can_previous}
166 >
167 {"◀"}
168 </button>
169 <span class="page-info-inline">
170 {format!("Page {} of {}", current_page + 1, page_count.max(1))}
171 </span>
172 <button
173 class={button_class(!can_next)}
174 onclick={on_next}
175 disabled={!can_next}
176 >
177 {"▶"}
178 </button>
179 <button
180 class={button_class(!can_next)}
181 onclick={on_last}
182 disabled={!can_next}
183 >
184 {"⟫"}
185 </button>
186 </div>
187
188 {if props.show_page_info {
189 html! {
190 <div class="page-info">
191 {format!("Showing {} to {} of {} entries", start_row, end_row, total_rows)}
192 </div>
193 }
194 } else {
195 html! {}
196 }}
197 </div>
198 }
199}