Synphonyte / leptos-struct-table

Easily create Leptos table components from structs
Apache License 2.0
154 stars 23 forks source link

Pagination doesn't handle short data #23

Closed notodog closed 4 months ago

notodog commented 6 months ago

When using DisplayStrategy::Pagination with row_count larger than the actually data size, the code panicked at table_content.rs:495:47, with messages like following:

range end index 9 out of range for slice of length 8

Wondering if the table should just render the excess rows empty by default?

Thanks for the great work!

maccesch commented 6 months ago

Thanks for reporting the bug.

Have you tried just not implementing the row_count method, when you really don't know how many rows there are? When this method is implemented the code assumes that this is the actual size of the data. If you don't know then you can return None from this method which is the default behavior.

notodog commented 6 months ago

Thanks @maccesch! I believe I failed to provide enough details. So this is my simplified data provider:

#[derive(Default, Clone)]
pub struct SimpleProvider {}

impl PaginatedTableDataProvider<user::Model> for SimpleProvider {
    const PAGE_ROW_COUNT: usize = 20;

    async fn get_page(&self, page_index: usize) -> Result<Vec<user::Model>, String> {
        match page_index {
            0 => Ok(vec![
                user::Model{ username: "abc1".to_string(), email: "abc1@def.com".to_string(), password: "password".to_string(), bio: None, image: None},
                user::Model{ username: "abc2".to_string(), email: "abc2@def.com".to_string(), password: "password".to_string(), bio: None, image: None},
            ]),
            _ => Ok(vec![])
        }
    }

    async fn row_count(&self) -> Option<usize> {
        Some(2)
    }
}

In the component I use a local resource to avoid SSR of the table:

    let provider = create_local_resource(
         || (),
         |_| async move {SimpleProvider::default()});

The in the view macro the table is created like following:

                    <div class="table-container" node_ref=container>
                        <Suspense fallback=move || view! {<p>"Loading Users"</p>}> {
                            move || match provider.get() {
                                None => view! { <Spinner size=SpinnerSize::Medium/> }.into_view(),
                                Some(rows) => view! {
                                    <Table>
                                        <TableContent
                                            rows
                                            scroll_container=container
                                            display_strategy=DisplayStrategy::Pagination {
                                                row_count: 10,
                                                controller: pagination_controller,
                                            }
                                        />
                                    </Table>
                                }.into_view(),
                            }
                        } </Suspense>
                    </div>

From the browser console, I'm getting the complaint like:

panicked at leptos-struct-table/src/components/table_content.rs:495:47:
range end index 10 out of range for slice of length 2

What did I do wrong?

notodog commented 6 months ago

BTW, if I simply let the table be rendered on both sides (CSR and SSR), like staging the provider with:

let provider = SimpleProvider::default();

Then invoke TableContent in the view! macro without differentiating:

                    <div class="table-container" node_ref=container>
                                    <Table>
                                        <TableContent
                                            rows=provider
                                            scroll_container=container
                                            display_strategy=DisplayStrategy::Pagination {
                                                row_count: 10,
                                                controller: pagination_controller,
                                            }
                                        />
                                    </Table>
                    </div>

It'll trigger the infamous hydration bug like the following:

panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_dom-0.6.7/src/html.rs:1392:13:
assertion `left == right` failed: SSR and CSR elements have the same hydration key but different node kinds. Check out the docs for information about this kind of hydration bug: https://leptos-rs.github.io/leptos/ssr/24_hydration_bugs.html
  left: "TH"
 right: "TR"

That's what led to use create_local_resource to disable the SSR in the previous comment. Thanks for looking into it!

maccesch commented 6 months ago

Interesting! Thanks for the details. I'll try and reproduce it.

maccesch commented 4 months ago

This has been fixed by #25