vincjo / datatables

A toolkit for creating datatable components with Svelte
https://vincjo.fr/datatables
MIT License
425 stars 15 forks source link

Data either disappears or showing the same data when using Sort function #47

Closed ghost closed 1 year ago

ghost commented 1 year ago

Hello,

My application has 4 tabs on 1 page, you can imagine it like Gmail, where in the Inbox it has Primary, Promotion, and Socials. After implementing the Sort function, the data on each tab either becomes exactly the same or completely disappears. If the initial is the same data on each tab, then after reload the data will disappears on each tab, and vice versa. Here are the screenshots of the problem:

Same data on each tab:

image image

Data disappears on each tab:

image image

Here are the codes I'm using:

TableSort.svelte :

<script>
    export let handler;
    export let orderBy = null;

    const identifier = orderBy?.toString();
    const sorted = handler.getSort();
</script>

<th on:click={() => handler.sort(orderBy)} class:active={$sorted.identifier === identifier}>
    <div class="d-flex align-items-center">
        <slot />
        <span class:asc={$sorted.direction === 'asc'} class:desc={$sorted.direction === 'desc'}></span>
    </div>
</th>

<style>
    th {
        background: inherit;
        cursor: pointer;
        margin: 0;
        padding: 14px 20px;
        user-select: none;
    }

    th span {
        margin-top: -2.5px;
        padding-left: 8px;
    }

    th span::before,
    th span::after {
        border: 4px solid transparent;
        content: '';
        display: block;
        width: 0;
        height: 0;
        margin-top: 2px;
    }

    th span::before {
        border-bottom-color: #e0e0e0;
    }

    th span::after {
        border-top-color: #e0e0e0;
    }

    th.active span.asc::before {
        border-bottom-color: #6e7891;
    }

    th.active span.desc::after {
        border-top-color: #6e7891;
    }
</style>

Index.svelte (the same for Published, Drafts, and Trash):

<script>
    import { DataHandler } from '@vincjo/datatables';
    import TableSort from '../../Components/TableSort.svelte';

    const handler = new DataHandler(productsAndSolutions, { rowsPerPage: 10 });
    const rows = handler.getRows();

    $: productsAndSolutions, handler.setRows(productsAndSolutions);
</script>

<TableSort {handler} orderBy="system" class="white-space-nowrap align-middle ps-4" scope="col" style="width: 350px;">SYSTEM</TableSort>

Is this a bug or there is something wrong with my code? Thank you.

vincjo commented 1 year ago

Hello

That's quite strange. I see no reason for the rows to disappear when a sort is applied. Your implementation looks right, so I guess the problem lies elsewhere

Do you apply some filter when users click on tabs? Or do you reload data?

ghost commented 1 year ago

@vincjo No, I don't apply filter (you can see that by looking at the number 0 with red background). The number besides All, Published, Drafts, and Trash are how many data from back end. When the user change tabs, the data is reload (without reloading the whole page). This is my back end if this might help (I'm using Laravel):

    public function index(Request $request)
    {
        $countAll = ProductAndSolution::all()->count();
        $countPublished = ProductAndSolution::where('published_at', '!=', null)->count();
        $countDrafts = ProductAndSolution::where('published_at', null)->count();
        $countTrash = ProductAndSolution::onlyTrashed()->count();

        if ($request->get('tab') === 'published') {
            return inertia('ProductsAndSolutions/Published', [
                'productsAndSolutions' => ProductAndSolution::where('published_at', '!=', null)
                    ->orderByDesc('id')
                    ->get()
                    ->map(fn ($productAndSolution) => [
                        'id' => $productAndSolution->id,
                        'image' => $productAndSolution->image,
                        'image_size' => $productAndSolution->image_size,
                        'starred' => $productAndSolution->starred,
                        'system' => $productAndSolution->system,
                        'description' => $productAndSolution->description,
                        'featured' => $productAndSolution->featured,
                        'updated_at' => $productAndSolution->updated_at,
                        'published_at' => $productAndSolution->published_at,
                    ]),
                'countAll' => $countAll,
                'countPublished' => $countPublished,
                'countDrafts' => $countDrafts,
                'countTrash' => $countTrash,
            ]);
        } elseif ($request->get('tab') === 'drafts') {
            return inertia('ProductsAndSolutions/Drafts', [
                'productsAndSolutions' => ProductAndSolution::where('published_at', '=', null)
                    ->orderByDesc('id')
                    ->get()
                    ->map(fn ($productAndSolution) => [
                        'id' => $productAndSolution->id,
                        'image' => $productAndSolution->image,
                        'image_size' => $productAndSolution->image_size,
                        'starred' => $productAndSolution->starred,
                        'system' => $productAndSolution->system,
                        'description' => $productAndSolution->description,
                        'featured' => $productAndSolution->featured,
                        'updated_at' => $productAndSolution->updated_at,
                    ]),
                'countAll' => $countAll,
                'countPublished' => $countPublished,
                'countDrafts' => $countDrafts,
                'countTrash' => $countTrash,
            ]);
        } elseif ($request->get('tab') === 'trash') {
            return inertia('ProductsAndSolutions/Trash', [
                'productsAndSolutions' => ProductAndSolution::onlyTrashed()
                    ->orderByDesc('id')
                    ->get()
                    ->map(fn ($productAndSolution) => [
                        'id' => $productAndSolution->id,
                        'image' => $productAndSolution->image,
                        'image_size' => $productAndSolution->image_size,
                        'starred' => $productAndSolution->starred,
                        'system' => $productAndSolution->system,
                        'description' => $productAndSolution->description,
                        'featured' => $productAndSolution->featured,
                        'updated_at' => $productAndSolution->updated_at,
                        'deleted_at' => $productAndSolution->deleted_at,
                    ]),
                'countAll' => $countAll,
                'countPublished' => $countPublished,
                'countDrafts' => $countDrafts,
                'countTrash' => $countTrash,
            ]);
        } else {
            return inertia('ProductsAndSolutions/Index', [
                'productsAndSolutions' => ProductAndSolution::orderByDesc('id')
                    ->get()
                    ->map(fn ($productAndSolution) => [
                        'id' => $productAndSolution->id,
                        'image' => $productAndSolution->image,
                        'image_size' => $productAndSolution->image_size,
                        'starred' => $productAndSolution->starred,
                        'system' => $productAndSolution->system,
                        'description' => $productAndSolution->description,
                        'featured' => $productAndSolution->featured,
                        'updated_at' => $productAndSolution->updated_at,
                        'published_at' => $productAndSolution->published_at,
                    ]),
                'countAll' => $countAll,
                'countPublished' => $countPublished,
                'countDrafts' => $countDrafts,
                'countTrash' => $countTrash,
            ]);
        }
    }

The problem only exist after I created the sort function. Before that, there is no problem even when I'm using filter, update the rows per page, etc.

vincjo commented 1 year ago

Ok so each tab's click returns a new set of data with same structure, re-injected into the DataHandler instance. That's ok. The sort should be re-applied after data updates. I'm gonna look what happens with a repro

vincjo commented 1 year ago

got no issues using sort() + switch tab + setRows(). https://vincjo.fr/datatables/test/tabs

Instead of

<script>
     $: productsAndSolutions, handler.setRows(productsAndSolutions);
</script>

Can you log the result when data is updated?

<script>
     $: productsAndSolutions, update();

     const update = () => {
          console.log('rawData', productsAndSolutions);
          handler.setRows(productsAndSolutions);
          const rows = handler.getRows();
          console.log('sortedData', $rows);
     }
</script>

Maybe i'll help, at least to see if re-applying sort() returns an empty array

ghost commented 1 year ago

@vincjo Here is what happens when the user first visits the page: image

And here is what happens when the user visits another tab: image

It's weird for the Draft tab to have data even though it shouldn't have one.

That is for the same data problem. For some unknown reason, the disappearing problem doesn't exist anymore after I'm using your code, but the same data problem still exists. The first picture has a total of 4 consoles while the second one only has two. I don't know if it's the problem or if it's intentionally like that.

vincjo commented 1 year ago

There is a side effect somewhere and i don't figure out where it happens.

Dupplicate consoles in landing page is normal cause there is the new Datahandler instantiation which use setRows() under the hood.

Is it ok for you to copy/paste the code in your tab component here? Still not sure where the issue happens but it could give an overview

ghost commented 1 year ago

Sorry for the late reply, but it's already been resolved for now. I don't know what is the differences, but when I just copy pasted your code from your example here: https://vincjo.fr/datatables/tutorial/sort-data

It works just like that. The only differences should be the class, styles, and I don't put inside the strong tag; honestly, that shouldn't create this kind of bug. But I don't think there are any other differences.