ag_grid_rs/gridoptions.rs
1//! Types pertaining to defining and constructing a `Grid`.
2
3use std::{collections::HashMap, future::Future};
4
5use ag_grid_core::imports::log;
6use ag_grid_derive::FieldSetter;
7use js_sys::Function;
8use wasm_bindgen::{prelude::*, JsCast};
9use wasm_bindgen_futures::spawn_local;
10use web_sys::HtmlElement;
11
12pub use crate::shared::SortMethod;
13use crate::{
14 callbacks::{GetRowsParams, IGetRowsParams},
15 column::ColumnDef,
16 convert::ToJsValue,
17 grid::AgGrid,
18 types::OneOrMany,
19 Grid, ToJsValue as ToJsValueMacro,
20};
21/// An instance of an AG Grid [`GridOptions`].
22///
23/// With this struct, users can specify the initial options for their grid,
24/// before calling the [`GridOptions::build()`] method to receive an instance of
25/// [`Grid`]. The various options are fully customisable using the builder
26/// pattern, so you only need to specify what you need. The options mirror those
27/// used in the AG Grid library.
28///
29/// [`GridOptions`]: https://www.ag-grid.com/javascript-data-grid/grid-options/
30#[derive(FieldSetter, ToJsValueMacro)]
31#[js_value(skip_serializing_none)]
32pub struct GridOptions<T>
33where
34 T: ToJsValue,
35{
36 // Accessories
37 // TODO
38
39 // Clipboard
40 // TODO
41
42 // Column Definitions
43 /// Set the column definitions. Fields set here take precedence over those
44 /// set in `default_col_def`.
45 column_defs: Option<Vec<ColumnDef>>,
46 /// Set the default column definition. Fields set here have lower precedence
47 /// than fields set on a per-column basis in `column_defs`.
48 default_col_def: Option<ColumnDef>,
49 // default_col_group_def
50 // column_types
51 /// Keeps the order of Columns maintained after new Column Definitions are
52 /// updated.
53 maintain_column_order: Option<bool>,
54
55 /// If `true`, then dots in field names (e.g. 'address.firstLine') are not
56 /// treated as deep references. Allows you to use dots in your field name if
57 /// you prefer.
58 suppress_dot_field_notation: Option<bool>,
59
60 // Column Headers
61 /// The height in pixels for the row containing the column label header. If
62 /// not specified, it uses the theme value of `header-height`.
63 header_height: Option<u32>,
64
65 /// The height in pixels for the rows containing header column groups. If
66 /// not specified, it uses [`GridOptions::header_height`].
67 group_header_height: Option<u32>,
68
69 /// The height in pixels for the row containing the floating filters. If not
70 /// specified, it uses the theme value of `header-height`.
71 floating_filters_height: Option<u32>,
72
73 // Column Moving
74 /// Set to `true` to suppress column moving, i.e. to make the columns fixed
75 /// position.
76 suppress_movable_columns: Option<bool>,
77
78 /// If `true`, the `ag-column-moving` class is not added to the grid while
79 /// columns are moving. In the default themes, this results in no animation
80 /// when moving columns.
81 suppress_column_move_animation: Option<bool>,
82
83 /// If `true`, when you drag a column out of the grid (e.g. to the group
84 /// zone) the column is not hidden.
85 suppress_drag_leave_hides_columns: Option<bool>,
86
87 /// If `true`, when you drag a column into a row group panel the column is
88 /// not hidden.
89 suppress_row_group_hides_columns: Option<bool>,
90
91 // Column Sizing
92 /// Set to 'Shift' to have shift-resize as the default resize operation
93 /// (same as user holding down `Shift` while resizing).
94 col_resize_default: Option<ResizeMethod>,
95
96 /// Suppresses auto-sizing columns for columns. In other words, double
97 /// clicking a column's header's edge will not auto-size.
98 suppress_auto_size: Option<bool>,
99
100 /// Number of pixels to add to a column width after the auto-sizing
101 /// calculation. Set this if you want to add extra room to accommodate (for
102 /// example) sort icons, or some other dynamic nature of the header.
103 auto_size_padding: Option<u32>,
104
105 /// Set this to `true` to skip the `header_name` when `auto_size` is called
106 /// by default.
107 skip_header_on_auto_size: Option<bool>,
108
109 // Components
110 // TODO
111
112 // Editing
113 /// Set to 'FullRow' to enable Full Row Editing. Otherwise leave blank to
114 /// edit one cell at a time.
115 edit_type: Option<EditType>,
116
117 /// Set to `true` to enable Single Click Editing for cells, to start editing
118 /// with a single click.
119 single_click_edit: Option<bool>,
120
121 /// Set to `true` so that neither single nor double click starts editing.
122 suppress_click_edit: Option<bool>,
123
124 /// Set to `true` to stop cell editing when grid loses focus. The default is
125 /// that the grid stays editing until focus goes onto another cell.
126 stop_editing_when_cells_lose_focus: Option<bool>,
127
128 /// Set to `true` along with [`GridOptions::enter_moves_down_after_edit`] to
129 /// have Excel-style behaviour for the `Enter` key, i.e. pressing the
130 /// `Enter` key will move down to the cell beneath.
131 enter_moves_down: Option<bool>,
132
133 /// Set to `true` along with [`GridOptions::enter_moves_down`] to have
134 /// Excel-style behaviour for the `Enter` key, i.e. pressing the `Enter` key
135 /// will move down to the cell beneath.
136 enter_moves_down_after_edit: Option<bool>,
137
138 /// Set to `true` to enable Undo / Redo while editing.
139 undo_redo_cell_editing: Option<bool>,
140
141 /// Set the size of the undo / redo stack.
142 undo_redo_cell_editing_limit: Option<u32>,
143
144 /// Set to `true` to stop the grid updating data after and edit. When this
145 /// is set, it is intended the application will update the data, e.g. in an
146 /// external immutable store, and then pass the new dataset to the grid.
147 read_only_edit: Option<bool>,
148
149 // Export
150 /// Prevent the user from exporting the grid to CSV.
151 suppress_csv_export: Option<bool>,
152
153 /// Prevent the user from exporting the grid to Excel.
154 suppress_excel_export: Option<bool>,
155 // TODO
156
157 // Filtering
158 // TODO
159
160 // Integrated Charts
161 // TODO
162
163 // Keyboard Navigation
164 // TODO
165
166 // Loading Cell Renderers
167 // TODO
168
169 // Localisation
170 // TODO
171
172 // Master Detail
173 // TODO
174
175 // Miscellaneous
176 /// Provide a context object that is provided to different callbacks the
177 /// grid uses. Used for passing additional information to the callbacks by
178 /// your application.
179 context: Option<HashMap<String, String>>,
180
181 /// Change this value to set the tabIndex order of the Grid within your
182 /// application.
183 tab_index: Option<u32>,
184
185 /// The number of rows rendered outside the viewable area the grid renders.
186 /// Having a buffer means the grid will have rows ready to show as the user
187 /// slowly scrolls vertically.
188 row_buffer: Option<u32>,
189
190 /// Set to `true` to enable debug information from the grid and related
191 /// components. Will result in additional logging being output, but very
192 /// useful when investigating problems.
193 debug: Option<bool>,
194
195 // Overlays
196 // TODO
197
198 // Pagination
199 /// Set whether pagination is enabled.
200 pagination: Option<bool>,
201
202 /// How many rows to load per page. If
203 /// [`GridOptions::pagination_auto_page_size`] is specified, this property
204 /// is ignored.
205 pagination_page_size: Option<u32>,
206
207 /// Set to `true` so that the number of rows to load per page is
208 /// automatically adjusted by the grid so each page shows enough rows to
209 /// just fill the area designated for the grid. If `false`,
210 /// [#GridOption::pagination_page_size`] is used.
211 pagination_auto_page_size: Option<bool>,
212
213 /// Set to `true` to have pages split children of groups when using Row
214 /// Grouping or detail rows with Master Detail.
215 paginate_child_rows: Option<bool>,
216
217 /// If `true`, the default grid controls for navigation are hidden. This is
218 /// useful if `pagination=true` and you want to provide your own pagination
219 /// controls. Otherwise, when `pagination=true` the grid automatically shows
220 /// the necessary controls at the bottom so that the user can navigate
221 /// through the different pages.
222 suppress_pagination_panel: Option<bool>,
223
224 // Pivot and Aggregation
225 // TODO
226
227 // Rendering
228 /// Set to `true` to enable Row Animation.
229 animate_rows: Option<bool>,
230
231 /// Set to `true` to have cells flash after data changes.
232 enable_cell_change_flash: Option<bool>,
233
234 /// To be used in combination with
235 /// [`GridOptions::enable_cell_change_flash`], this configuration
236 /// will set the delay in milliseconds of how long a cell should remain in
237 /// its "flashed" state.
238 cell_flash_delay: Option<u32>,
239
240 /// To be used in combination with
241 /// [`GridOptions::enable_cell_change_flash`], this configuration
242 /// will set the delay in milliseconds of how long the "flashed" state
243 /// animation takes to fade away after the timer set by
244 /// [`GridOptions::cell_flash_delay`] has completed.
245 cell_fade_delay: Option<u32>,
246
247 /// Set to `true` to have cells flash after data changes even when the
248 /// change is due to filtering.
249 allow_show_change_after_filter: Option<bool>,
250
251 /// Switch between layout options.
252 dom_layout: Option<DomLayout>,
253
254 /// When `true`, the order of rows and columns in the DOM are consistent
255 /// with what is on screen.
256 ensure_dom_order: Option<bool>,
257
258 /// Set to `true` to operate the grid in RTL (Right to Left) mode.
259 enable_rtl: Option<bool>,
260
261 /// Set to `true` so that the grid doesn't virtualise the columns. For
262 /// example, if you have 100 columns, but only 10 visible due to scrolling,
263 /// all 100 will always be rendered.
264 suppress_column_virtualisation: Option<bool>,
265
266 /// Set to `true` so that the grid doesn't virtualise the rows. For example,
267 /// if you have 100 rows, but only 10 visible due to scrolling, all 100 will
268 /// always be rendered.
269 suppress_row_virtualisation: Option<bool>,
270
271 /// By default the grid has a limit of rendering a maximum of 500 rows at
272 /// once (remember the grid only renders rows you can see, so unless your
273 /// display shows more than 500 rows without vertically scrolling this will
274 /// never be an issue). This is only relevant if you are manually setting
275 /// [`GridOptions::row_buffer`] to a high value (rendering more rows than
276 /// can be seen) or if your grid height is able to display more than 500
277 /// rows at once.
278 suppress_max_rendered_row_restriction: Option<bool>,
279
280 // Row Drag and Drop
281 /// Set to `true` to enable Managed Row Dragging.
282 row_drag_managed: Option<bool>,
283
284 /// Set to `true` to enable clicking and dragging anywhere on the row
285 /// without the need for a drag handle.
286 row_drag_entire_row: Option<bool>,
287
288 /// Set to `true` to enable dragging multiple rows at the same time.
289 row_drag_multi_row: Option<bool>,
290
291 /// Set to `true` to suppress row dragging.
292 suppress_row_drag: Option<bool>,
293
294 /// Set to `true` to suppress moving rows while dragging the row drag
295 /// waffle. This option highlights the position where the row will be
296 /// placed and it will only move the row on mouse up.
297 suppress_move_when_row_dragging: Option<bool>,
298
299 // Row Full Width
300 // TODO
301
302 // Row Pinning
303 // TODO
304
305 // RowModel
306 /// Sets the row model type.
307 row_model_type: Option<RowModelType>,
308 // get_row_id
309
310 // RowModel: Client Side
311 /// Set the row data.
312 row_data: Option<Vec<T>>,
313
314 // RowModel: Infinite
315 datasource: Option<DataSource>,
316 /// How many extra blank rows to display to the user at the end of the
317 /// dataset, which sets the vertical scroll and then allows the grid to
318 /// request viewing more rows of data.
319 cache_overflow_size: Option<u32>,
320
321 /// How many requests to hit the server with concurrently. If the max is
322 /// reached, requests are queued. Set to `-1` for no maximum restriction on
323 /// requests.
324 max_concurrent_datasource_requests: Option<i32>,
325
326 /// How many rows for each block in the store, i.e. how many rows returned
327 /// from the server at a time.
328 cache_block_size: Option<u32>,
329
330 /// How many blocks to keep in the store. Default is no limit, so every
331 /// requested block is kept. Use this if you have memory concerns, and
332 /// blocks that were least recently viewed will be purged when the limit is
333 /// hit. The grid will additionally make sure it has all the blocks needed
334 /// to display what is currently visible, in case this property is set to a
335 /// low value.
336 max_blocks_in_cache: Option<u32>,
337
338 /// How many extra blank rows to display to the user at the end of the
339 /// dataset, which sets the vertical scroll and then allows the grid to
340 /// request viewing more rows of data.
341 infinite_initial_row_count: Option<u32>,
342 // TODO
343
344 // RowModel: Server Side
345 // TODO
346
347 // RowModel: Viewport
348 // TODO
349
350 // Scrolling
351 /// Set to `true` to always show the horizontal scrollbar.
352 always_show_horizontal_scroll: Option<bool>,
353
354 /// Set to `true` to always show the vertical scrollbar.
355 always_show_vertical_scroll: Option<bool>,
356
357 /// Set to `true` to debounce the vertical scrollbar. Can provide smoother
358 /// scrolling on slow machines.
359 debounce_vertical_scrollbar: Option<bool>,
360
361 /// Set to `true` to never show the horizontal scroll. This is useful if the
362 /// grid is aligned with another grid and will scroll when the other grid
363 /// scrolls. (Should not be used in combination with
364 /// [`GridOptions::always_show_horizontal_scroll`].)
365 suppress_horizontal_scrollbar: Option<bool>,
366
367 /// When `true`, the grid will not scroll to the top when new row data is
368 /// provided. Use this if you don't want the default behaviour of scrolling
369 /// to the top every time you load new data.
370 suppress_scroll_on_new_data: Option<bool>,
371
372 /// When `true`, the grid will not allow mousewheel / touchpad scroll when
373 /// popup elements are present.
374 suppress_scroll_when_popups_are_open: Option<bool>,
375
376 /// When `true`, the grid will not use animation frames when drawing rows
377 /// while scrolling. Use this if the grid is working fast enough that you
378 /// don't need animation frames and you don't want the grid to flicker.
379 suppress_animation_frame: Option<bool>,
380
381 /// When `true`, middle clicks will result in click events for cells and
382 /// rows. Otherwise the browser will use middle click to scroll the grid.
383 /// Note: Not all browsers fire click events with the middle button. Most
384 /// will fire only mousedown and mouseup events, which can be used to focus
385 /// a cell, but will not work to call the onCellClicked function.
386 suppress_middle_click_scrolls: Option<bool>,
387
388 /// When `true`, mouse wheel events will be passed to the browser. Useful if
389 /// your grid has no vertical scrolls and you want the mouse to scroll the
390 /// browser page.
391 suppress_prevent_default_on_mouse_wheel: Option<bool>,
392
393 /// Tell the grid how wide in pixels the scrollbar is, which is used in grid
394 /// width calculations. Set only if using non-standard browser-provided
395 /// scrollbars, so the grid can use the non-standard size in its
396 /// calculations.
397 scrollbar_width: Option<u32>,
398
399 // Selection
400 /// Type of row selection.
401 row_selection: Option<RowSelection>,
402
403 /// Set to `true` to allow multiple rows to be selected using single click.
404 row_multi_select_with_click: Option<bool>,
405
406 // is_row_selectable
407 /// If `true`, rows will not be deselected if you hold down `Ctrl` and click
408 /// the row or press `Space`.
409 suppress_row_deselection: Option<bool>,
410
411 /// If `true`, row selection won't happen when rows are clicked. Use when
412 /// you only want checkbox selection.
413 suppress_row_click_selection: Option<bool>,
414
415 /// If `true`, cells won't be focusable. This means keyboard navigation will
416 /// be disabled for grid cells, but remain enabled in other elements of the
417 /// grid such as column headers, floating filters, tool panels.
418 suppress_cell_focus: Option<bool>,
419
420 /// Set to `true` to be able to select the text within cells. Note: When
421 /// this is set to true, the clipboard service is disabled.
422 enable_cell_text_selection: Option<bool>,
423
424 // Sorting
425 /// Vector defining the order in which sorting occurs (if sorting is
426 /// enabled).
427 sorting_order: Option<Vec<SortMethod>>,
428
429 /// Set to `true` to specify that the sort should take accented characters
430 /// into account. If this feature is turned on the sort will be slower.
431 accented_sort: Option<bool>,
432
433 /// Set to `true` to show the 'no sort' icon.
434 #[js_value(rename = "unSortIcon")]
435 unsort_icon: Option<bool>,
436
437 /// Set to `true` to suppress multi-sort when the user shift-clicks a column
438 /// header.
439 suppress_multi_sort: Option<bool>,
440
441 /// Set to `true` to always multi-sort when the user clicks a column header,
442 /// regardless of key presses.
443 always_multi_sort: Option<bool>,
444
445 /// Set to 'Ctrl' to have multi sorting work using the `Ctrl` (or `Command
446 /// ⌘` for Mac) key.
447 multi_sort_key: Option<MultiSortKey>,
448
449 /// Set to `true` to suppress sorting of un-sorted data to match original
450 /// row data.
451 suppress_maintain_unsorted_order: Option<bool>,
452
453 /// When enabled, sorts only the rows added/updated by a transaction.
454 delta_sort: Option<bool>,
455
456 // Styling
457 /// Default row height in pixels.
458 row_height: Option<u32>,
459
460 /// CSS class(es) for all rows. Provide either a string (class name) or
461 /// vector of strings (vector of class names).
462 row_class: Option<OneOrMany<String>>,
463
464 /// Set to `true` to not highlight rows by adding the `ag-row-hover` CSS
465 /// class.
466 suppress_row_hover_highlight: Option<bool>,
467
468 /// Uses CSS `top` instead of CSS `transform` for positioning rows. Useful
469 /// if the transform function is causing issues such as used in `row
470 /// spanning`.
471 suppress_row_transform: Option<bool>,
472
473 /// Set to `true` to highlight columns by adding the `ag-column-hover` CSS
474 /// class.
475 column_hover_highlight: Option<bool>,
476
477 // Tooltips
478 /// Set to `true` to use the browser's default tooltip instead of using the
479 /// grid's Tooltip Component.
480 enable_browser_tooltips: Option<bool>,
481
482 /// The delay in milliseconds that it takes for tooltips to show up once an
483 /// element is hovered over. Note: This property does not work if
484 /// [`GridOptions::enable_browser_tooltips`] is `true`.
485 tooltip_show_delay: Option<u32>,
486
487 /// The delay in milliseconds that it takes for tooltips to hide once they
488 /// have been displayed. Note: This property does not work if
489 /// [`GridOptions::enable_browser_tooltips`] is `true`.
490 tooltip_hide_delay: Option<u32>,
491
492 /// Set to `true` to have tooltips follow the cursor once they are
493 /// displayed.
494 tooltip_mouse_track: Option<bool>,
495}
496
497impl<T> GridOptions<T>
498where
499 T: ToJsValue,
500{
501 pub fn new() -> Self {
502 Default::default()
503 }
504
505 /// A finaliser method for the [`GridOptions`] struct. This method
506 /// constructs the underlying JavaScript grid and returns a handle,
507 /// [`Grid`], which provides access to the grid APIs.
508 pub fn build(self, div: HtmlElement) -> Grid {
509 let grid_options = self.to_js_value();
510
511 let js_grid = AgGrid::new(div, grid_options);
512
513 Grid {
514 api: js_grid.gridOptions().api(),
515 column_api: js_grid.gridOptions().columnApi(),
516 }
517 }
518}
519
520/// Allowed values for [`GridOptions::multi_sort_key`].
521#[derive(ToJsValueMacro)]
522pub enum MultiSortKey {
523 Ctrl,
524}
525
526/// Allowed values for [`GridOptions::dom_layout`].
527#[derive(ToJsValueMacro)]
528pub enum DomLayout {
529 Normal,
530 Print,
531 AutoHeight,
532}
533
534/// Allowed values for [`GridOptions::edit_type`].
535#[derive(ToJsValueMacro)]
536pub enum EditType {
537 FullRow,
538}
539
540/// Allowed values for [`GridOptions::col_resize_default`].
541#[derive(ToJsValueMacro)]
542pub enum ResizeMethod {
543 Shift,
544}
545
546/// Allowed values for [`GridOptions::row_selection`].
547#[derive(ToJsValueMacro)]
548pub enum RowSelection {
549 Single,
550 Multiple,
551}
552
553/// Allowed values for [`GridOptions::row_model_type`].
554#[derive(ToJsValueMacro)]
555pub enum RowModelType {
556 Infinite,
557 Viewport,
558 ClientSide,
559 ServerSide,
560}
561
562/// A struct passed to the JavaScript grid which is used by AG Grid to fetch the
563/// requested data from the server.
564#[wasm_bindgen]
565#[derive(ToJsValueMacro)]
566pub struct DataSource {
567 #[wasm_bindgen(readonly, getter_with_clone, js_name = getRows)]
568 pub get_rows: Function,
569}
570
571/// Builder for the [`DataSource`].
572pub struct DataSourceBuilder {
573 // Callback the grid calls that the user implements to fetch rows from the
574 // server.
575 get_rows: Closure<dyn FnMut(IGetRowsParams)>,
576 // row_count is deprecated. Use GridOptions.infiniteInitialRowCount instead:
577 // https://github.com/ag-grid/ag-grid/blob/7358e4286fd52946c4fe24bd26b5fbe7fd3b22d4/community-modules/core/src/ts/interfaces/iDatasource.ts#L7-L9
578 //row_count: Option<u32>,
579}
580
581impl DataSourceBuilder {
582 /// Start constructing a new `DataSourceBuilder` by providing a callback
583 /// function which will receive [`GetRowsParams`]. This callback is
584 /// called by AG Grid to request new rows from the server.
585 pub fn new<F, Fut, T>(mut get_rows: F) -> Self
586 where
587 F: FnMut(GetRowsParams) -> Fut + 'static,
588 Fut: Future<Output = Result<(Vec<T>, Option<u32>), Box<dyn std::error::Error>>> + 'static,
589 T: ToJsValue,
590 {
591 let get_rows =
592 Closure::<dyn FnMut(IGetRowsParams)>::new(move |js_params: IGetRowsParams| {
593 let params = (&js_params).into();
594 let fut = get_rows(params);
595
596 let wrapper = async move {
597 match fut.await {
598 Ok((data, last_row_index)) => {
599 let data = data.to_js_value();
600 let last_row_index = last_row_index.to_js_value();
601 js_params
602 .success_callback()
603 .call2(&JsValue::null(), &data, &last_row_index)
604 .expect("failed calling success callback");
605 }
606 Err(e) => {
607 log(&format!("Error calling get_rows callback: {e:?}"));
608 js_params
609 .fail_callback()
610 .call0(&JsValue::null())
611 .expect("failed calling failure callback");
612 }
613 };
614 };
615
616 spawn_local(wrapper)
617 });
618
619 Self { get_rows }
620 }
621
622 /// Finalise construction of a [`DataSource`].
623 pub fn build(self) -> DataSource {
624 DataSource {
625 get_rows: self.get_rows.into_js_value().unchecked_into(),
626 }
627 }
628}