GithubHelp home page GithubHelp logo

vincjo / datatables Goto Github PK

View Code? Open in Web Editor NEW
318.0 8.0 16.0 6.62 MB

A toolkit for creating datatable components with Svelte

Home Page: https://vincjo.fr/datatables

License: MIT License

JavaScript 0.06% HTML 0.02% Svelte 6.25% TypeScript 93.35% CSS 0.32%
datatable datatables svelte sveltejs table filter pagination sort headless

datatables's Introduction

logo

svelte simple datatables

A toolkit for creating datatable components with Svelte

npm version last commit

Presentation

This lib provides an API to dynamically interact with iterable data on the client-side: filtering, paging, sorting, selecting...

  • Headless by design
  • Typescript support
  • SSR friendly
  • no dependencies

Also provides some showcase components, which you can grab and customize in your own project.

🌐 Live examples


📡 Server-side data processing

logo

Support for server-side pagination, sort, filters is located in @vincjo/datatables/remote namespace.

Basic usage | Examples


Install

npm i -D @vincjo/datatables

Sample code

<script lang="ts">
    import { DataHandler } from '@vincjo/datatables'
    import { someData } from './data'

    const handler = new DataHandler(someData, { rowsPerPage: 50 })
    const rows = handler.getRows()
</script>

<table>
    <thead>
        <tr>
            <th>First name</th>
            <th>Last name</th>
        </tr>
    </thead>
    <tbody>
        {#each $rows as row}
            <tr>
                <td>{row.first_name}</td>
                <td>{row.last_name}</td>
            </tr>
        {/each}
    </tbody>
</table>

DataHandler methods

getRows(): Readable<Row[]>
setRows( data: Row[] ): void
sort( orderBy: Field<Row> ): void
sortAsc( orderBy: Field<Row> ): void
sortDesc( orderBy: Field<Row> ): void
getSort(): Writable<(Sort<Row>)>
applySort( params: { orderBy?: Field<Row>, direction?: 'asc' | 'desc'} = null ): void
defineSort( params: { orderBy?: Field<Row>, direction?: 'asc' | 'desc'} = null ): void
clearSort(): void
filter( value: string, filterBy: Field<Row>, comparator: Comparator<Row> ): void
clearFilters(): void
getFilterCount(): Readable<number>
search( value: string, scope?: Field<Row>[] ): void
clearSearch(): void
getRowsPerPage(): Writable<number | null>
getRowCount(): Readable<{ total: number; start: number; end: number; }>
getPages( param: { ellipsis: boolean } ): Readable<number[]>
getPageCount(): Readable<number>
getPageNumber(): Readable<number>
setPage( value: number | ‘previous’ | ‘next’ ): void
select(value: Row[] | (Row[keyof Row])[]): void
getSelected(): Writable<Row[] | (Row[keyof Row])[]>
selectAll(params: { selectBy?: keyof Row, scope?: 'all' | 'currentPage' } = { scope: 'all' }): void
isAllSelected(): Readable<boolean>
on(event: 'change' | 'clearFilters' | 'clearSearch', callback: () => void)

datatables's People

Contributors

ditatompel avatar droher avatar dzialdowski avatar gusbuncedev avatar vdelacerda avatar vincjo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

datatables's Issues

[Suggestion] Improve types

Summary

Currently the library liberally uses any, Function and string types. There is nothing wrong with doing it this way, however the developer experience could be meaningfully improved by implementing generics.

I've made a slice of what the implementation might look like in my fork. My vscode formatted it to 2 space indent, so it might look ugly, sorry for that.

What the actual improvement is?

User land code in both examples is the same, only $lib/core has been changed.

With current implementation the data type is any and keys are string. Because of that we get no type checking and autocomplete.
image

After adding some generics we get both.
image

How does that work?

Since the DataHandler instance gets passed around anyway, it makes sense to attach the type to it.

export default class DataHandler<T extends { [key: string]: unknown } = any>

With that adapting Th component to use the type is pretty straightforward.

<script lang="ts">
  type T = $$Generic<{ [key: string]: unknown }>;
  type OrderBy<Row> = keyof Row | ((row: Row) => Row[keyof Row]);

  import type { DataHandler } from '$lib/core';
  export let handler: DataHandler<T>;
  export let orderBy: OrderBy<T>;
  export let align: 'left' | 'right' | 'center' = 'left';
  const identifier = orderBy ? orderBy.toString() : orderBy;

  const sorted = handler.getSorted();
</script>

What's next?

It shouldn't be that hard to extend the same idea to the rest of the library, and I have plentiful free time right now, so I can implement the changes. But that's still a big change and I wanted to discuss it here first.

@vincjo As the author an maintainer of the library, do you feel like the library would benefit from stricter types (like ones in the example above)?

If you have any questions - feel free to ask. And thank you for the awesome work on the library.

List Filters

First - I Love this datatable and thank you for all the support.

Is there a way to do either of the following:

  1. List each filter parameter - I see a getFilterCount that shows how many filters are applied but I want to see what each filter is.
  2. Clear a single filter when the filter count is greater than 2?

CSS Styling once again

I am looking for a proper way of styling all the components to my needs. This was an issue with Issue #29, but I am struggling to get this working.

It seems that there is ongoing debate in the svelte community how to pass CSS classes or whatsoever to child components. There are so many approaches with flaws etc.

I've found a very interesting and recent video - This Week in Svelte (2023 June 9) - Updates, Self-hosting SvelteKit, Passing styles to children - https://youtu.be/OG70PKD0hEU?t=2836.

My ultimate goal is to style the Datatable component from the outside by overwriting the built-in CSS attributes.

Of course, I could create my own Datatable components and regain full control over styling, but once you update the components and I would have to repeat the whole process. That would be cumbersome overall, I think.

Hoping for some support and suggestions :)

Thanks

How to access value of Th Filter

In the following scenario, the filter is still applied, but the value is not displayed:

  1. Fill the Id filter with something, for example "ab". (The filter is applied correctly.)
  2. Click the New button to register a new element.
  3. I hit the Back button.
  4. It is observed that the filter is still applied, BUT the value "ab" has disappeared:

Some help will be appreciatted. Maybe some public method in Filters.ts to access the value of each filter or something like that...

Thanks in advance!

image
image
image

How do you remove any applied filters?

Not sure if I'm missing something, but how do you remove any applied filters?

For example, I'm not using the table headers/input field to filter data - but programmatically using radio buttons, and so I need to be able to programmatically reset the filters

How to add checkboxes to 'Reactivity example with a simple CRUD'

Hello. I've spent several days trying to extend the example 'Reactivity example with a simple CRUD' with checkboxes.

Basically, add to each row the typical checkbox:

                     <td>
                        <input
                            class="form-check-input"
                            type="checkbox"
                            value={row.id}
                            id={row.id} />
                    </td>

The problem is that when changing the page, (and then return to that page) the checked checkboxes are no longer taken into account.

What would be the way to do it?

I have tried several things without success. For example:

bind:checked={$users[row.id]}

Any help is appreciated.

How to pass scope for Search from another file?

Hello, my application is divided into Components and Pages folders. Components folder contains files that are reusable. In this case, I use it to create Filter, Search, RowCount, etc from your example. One thing that I haven't been able to do is to use scope in SearchComponent where I define the scope from Pages.

For example, this is what I was trying to do:

SearchComponent:

<script>
    export let handler;
    export let scope;

    let value = '';
</script>

<input type="search" class="form-control search-input" bind:value on:input={() => handler.search(value, {scope})} placeholder="Search..." aria-label="Search">

ProductsPage:

<TableSearch {handler} scope="['system', 'brands']" />

But it doesn't work. Another thing that I've tried was:

SearchComponent:

<script>
    export let handler;
    export let scope;

    let value = '';
</script>

<input type="search" class="form-control search-input" bind:value on:input={() => handler.search(value, [{scope}])} placeholder="Search..." aria-label="Search">

ProductsPage:

<TableSearch {handler} scope="'system', 'brands'" />

But it doesn't work either.

If I hard coded it into SearchComponent, then it will work. But the thing is, I wanted to make the scope dynamic so it can work for different kind of Pages. How do I do that? Thank you.

[ERROR] Could not resolve "$lib"

After updating to the latest version 1.9.4 (coming from 1.7.2), I am getting an error.

VITE v4.3.9 ready in 677 ms

➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
X [ERROR] Could not resolve "$lib"

node_modules/@vincjo/datatables/Datatable.svelte:39:58:
  39 │ import { Search, RowsPerPage, RowCount, Pagination } from '$lib';
     ╵                                                           ~~~~~~

You can mark the path "$lib" as external to exclude it from the bundle, which will remove this
error.

[Suggestion] CSS classes on components

Hello!

This was already mentioned in Issue #14, but it would be very helpful if styling could be applied to different components (Pagination, Search, RowsPerPage, ThFilter etc) without remaking all of those components.

The project I'm working on uses the Skeleton UI toolkit. The developers of Skeleton suggested using your datatable as a great replacement to what they are intending to make (since they have not implemented theirs yet), but currently, on a project with a dark background design, this datatable component is very hard to work with - I would have to remake many things from scratch just to change the font color to something readable.

Thanks!

[SUGGESTION] Add support for different text in Datatable

Hey!
This project is great make good data tables fast and im using it in a few of my projects which are in german but every text of the data table is english.. Is there some way to change that without really changing the actual source code ( because that would mean that people would have to make the same changes when downloading my project.. ) or is there already some functionality I did not know of?

$$Generic does not exist

There are 15 files that have the following code: 15 results - 15 files

src/lib/local/Datatable.svelte:
3
4: type T = $$Generic
5

src/lib/local/Pagination.svelte:
3
4: type T = $$Generic
5

src/lib/local/RowCount.svelte:
3
4: type T = $$Generic
5

src/lib/local/RowsPerPage.svelte:
3
4: type T = $$Generic
5

src/lib/local/Search.svelte:
3
4: type T = $$Generic
5

src/lib/local/Th.svelte:
3
4: type T = $$Generic
5

src/lib/local/ThFilter.svelte:
3
4: type T = $$Generic
5

src/lib/remote/Datatable.svelte:
3
4: type T = $$Generic
5

src/lib/remote/Pagination.svelte:
3
4: type T = $$Generic
5

src/lib/remote/RowCount.svelte:
3
4: type T = $$Generic
5

src/lib/remote/RowsPerPage.svelte:
3
4: type T = $$Generic
5

src/lib/remote/Search.svelte:
3
4: type T = $$Generic
5

src/lib/remote/Th.svelte:
3
4: type T = $$Generic
5

src/lib/remote/ThFilter.svelte:
3
4: type T = $$Generic
5

src/routes/(local)/test/search-scope/Search.svelte:
3
4: type T = $$Generic
5

    type T = $$Generic<Row>
    export let handler: DataHandler<T>

What is $$Generic for?

Why its not:

export let handler: DataHandler<Row>

Directly without the T?

Issues with sticky header and footer

Hi,

I am currently implementing this library in a project of mine. First of all great work!
I am trying to make the header and "footer" sticky, but in the documentation the sample code of “basic” and “sticky” is the same (also confirmed it in the SvelteKit code, the file is always the same).
The CSS under “tips” also does not work for me.

It would be wonderful if you could explain how the sticky header and footer is meant to be implemented.

Thank you in advance

Bug: setRows() changes getSorted store

I've discovered an issue where if setRows() is used to apply new data the contents of the getSorted store goes from this (for example):

{identifier: 'Supplier Name', direction: 'asc', fn: ƒ}

to this:

{identifier: '(row) => row[orderBy]', direction: 'asc', fn: ƒ}

The data in the table itself is sorted correctly, but visually (the component) no longer displays the correct sorting direction (based on your example)

Lots of interest

Bonjour @vincjo ,

I'm not sure if you are familiar with Skeleton. It's a relatively new but very polished UI toolkit built on SvelteKit and Tailwind. There was some discussion about trying to integrate a third-party data table component, and I recommended your excellent project for consideration. There was a lot of feedback about pros and cons, and I thought you mind find it interesting:

skeletonlabs/skeleton#538 (comment)

Not asking for any work, just thought you should know!

Multiple advanced filters with the same filter function not working together

I have tag categories that are each their own column, for example department and job level. I want to have an advanced filter for each column and have the filters work together, for example (department = product OR design) AND (job level = senior). If I manually define the filters with unique filter functions they work as expected. If I give them the same filter function or I create them dynamically (which I need to do) they work individually but not together with the other filters, it's the same behaviour as removing the other filters first.

Works ✅

const departmentFilter = handler.createAdvancedFilter((row) =>
    row.tags.filter((x) => x.tagCategoryId === 1).map((x) => x.tagId),
);
const levelFilter = handler.createAdvancedFilter((row) =>
    row.tags.filter((x) => x.tagCategoryId === 2).map((x) => x.tagId),
);

Doesn't work ❌

const filterFns = [1, 2].map((tagCategory) =>
    handler.createAdvancedFilter((row) =>
	row.tags.filter((x) => x.tagCategoryId === tagCategory).map((x) => x.tagId),
    ),
);

Doesn't work ❌

const departmentFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((x) => x.tagId),
);
const levelFilter = handler.createAdvancedFilter((row) =>
    row.tags.map((x) => x.tagId),
);

'slice' error when no record is received

Hello
I get an error when there is no record.

---------------handler---------------------------
{"context":{"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}},"rowsPerPage":{},"pageNumber":{},"search":{},"filters":{},"filterCount":{},"rawRows":{},"filteredRows":{},"pagedRows":{},"rowCount":{},"pages":{},"pagesWithEllipsis":{},"pageCount":{},"sort":{},"selected":{},"selectScope":{},"isAllSelected":{}},"sortHandler":{"rawRows":{},"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}},"sort":{},"backup":[]},"selectHandler":{"filteredRows":{},"pagedRows":{},"selected":{},"scope":{},"isAllSelected":{},"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}}},"pageHandler":{"pageNumber":{},"rowCount":{},"rowsPerPage":{},"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}}},"searchHandler":{"search":{},"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}}},"filterHandler":{"filters":{},"event":{"events":{"change":[],"clearFilters":[],"clearSearch":[]},"triggerChange":{}}},"i18n":{"search":"Search...","show":"Show","entries":"entries","filter":"Filter","rowCount":"Showing {start} to {end} of {total} entries","noRows":"No entries found","previous":"Previous","next":"Next"}}

TypeError: $filteredRows.slice is not a function

image

Disable Search and Pagination

Would be nice to be able to disable these feature by config !
in my particular case i don't need it so i masked it by CSS ...

Also had trouble figuring how to use reactivity using $: handler.setRows(data) ... maybe you can add a example in the docs !

On the whole pretty usefull library. Starred :)

Expose custom comparison function, for filtering

Hi there, and thanks for your support.

In https://github.com/vincjo/datatables/blob/master/src/lib/core/Context.ts, the method createFilteredRows uses stringMatch to filter relevant rows. We (me and @rkpasia, working on https://github.com/fractal-analytics-platform/fractal-web) would be interested in replacing stringMatch with a custom method. The reason for this is that we would like to select all rows where a certain column has a specific value.

Our use case is that (for instance) we have a column "ID", and rows with values 1, 2, ..., 10, 11, 12. We would like to be able to select the row with ID=1, without including the other IDs that match with 1 (e.g. 10 and 11). However, we don't see a way to achieve it with the current datatables. We could write a custom function, like

    private stringExactMatch(entry:string|Object, value: string) 
    {
    return entry === value
    }

but we could not use this comparison function instead of stringMatch.
If there exists a way to achieve this, and we missed it, suggestions are welcome! :)


Would you consider including the possibility of overriding the stringMatch method as part of the Context class?
How could this be exposed through the API, so that a user could replace stringMatch with a custom function? Could it be a comparisonFunction (undefined, by default) of Filters?

If this sounds interesting, we could try setting up a PR.

Sort null last

Can i sort/orderBy datatable with null values? it seems like it is not possible but i might be missing something here

Filtering table columns and numbers

Hey, first of all thanks for the great package, it has worked out great so far.

But I recently stumbled onto a smallish issue.

I have tables and columns with filtering, and filtering numbers does work from 1-9 but not if it gets higher.
For example I have these data rows with values: AVG8, AVG10, AVG11

The filtering works like that:
AVG8, AVG11, AVG10 OR AVG10, AVG11, AVG8

Meaning it's only taking into consideration the first part, not the whole number.
I also attached some images to understand it better.

image image

Search for integers don't work

In my data I have
{"id":1}
when i search 1 in filter or globa search, it doesn't work, and when i clear inputs it empties the table until I search for string.

Is there any way to count how many filter applied?

First of all, thank you for this great package. It's easy to use and headless, making it a piece of cake to integrate into existing templates. I'm making a slightly different filter than your example. My Filter is inside a modal and there are many types of it, select, date, etc. I'm able to implement them all, but I don't have any way to tell the user if the current table is filtered. I would like to display the number of filters applied to the current table. Does Svelte Datatables provide this or is there any JavaScript code that works for this? Thank you.

Filter Key for Nested Items

I'm trying to filter by 'bios' which is nested in the hw-info key. I'm not sure how to do it, I've tried setting the filter key to item['hwinfo'] and item.hwinfo with no luck. Is this possible?

item = { "id": "test-id", "hwinfo": { "bios": "3.4" } }

I know that I can filter with hwinfo and search for 3.4, however I will have more fields in the object and some fields may have 3.4 in them as well.

minor improvement: css-classes on Components

eg. the Pagination Component has no class whatsoever.
Would be cool if Components could be written in this way too:

<Pagination 
   class="dt_pagination"
   handler={ dataTable }  
/>

Inside of the Component it can be done in this way:

<section class="{ if $$props.class !== undefined ? $$props.class : '' }">

Don't know if this is the official way, but i found it on the webs and it was very useful for me.

gettings errors in Row.js

I'm getting errors when i try to re-set all Rows (reload json-Data) in Row.js
orderBy is null somehow and that fails. The data i'm fetching is exactly the same.

i fixed that temporarily by catching this case in this way:

parse(orderBy) {
        // ---- INSERT
        if(orderBy === null) {
            return {
                fn: () => {},
                identifier: 'null',
            }
        }
        // ----
        if (typeof (orderBy) === 'string') {
            return {
                fn: (row) => row[orderBy],
                identifier: orderBy.toString()
            };
        }
        return {
            fn: orderBy,
            identifier: orderBy.toString()
        };
    }

Column visibility

Is there any way to change the visibility of a column? I'm working with about 5 columns, and would like to hide 2 of them when the screen with is reduced to mobile/tablet size.

I seem to be able to pass class into the Th components, but CSS display: none doesn't apply for some reason.

Select Option Filter With Different Value Types

Hello, my database has published_at field that contains either date or null. If it's null, then I displayed it in Svelte Datatables by string "Unpublished". If it's not null then I just displayed the date itself.

Now I want to filter if it's published or not. It's easy for the null value because I just need to pass "Unpublished" for the select option value, but I have no idea how for the date value since every date is different. Right now I have a cheesy workaround, since every date that I displayed contains a comma, I set the select option value for not null to comma and that works, but I don't think this is the best? Does Svelte Datatables have function or solution for this kind of filter?

This is my code right now:

TableFilterSelect :

<script>
    export let handler;
    export let id;
    export let defaultSelectedText;
    export let options;
    export let filterBy = null;

    let value = '';
</script>

<select class="form-select" {id} bind:value on:change={() => handler.filter(value, filterBy)}>
    <option value="" disabled="{value === ''}" hidden="{value === ''}">{defaultSelectedText}</option>
    {#each options as option}
        <option value={option.value}>{option.text}</option>
    {/each}
</select>

Page :

<TableFilterSelect {handler} id="published_at" filterBy="published_at" defaultSelectedText="Select Published" options={[{"value": ",", "text": "Yes"}, {"value": "Unpublished", "text": "No"}]} />

Thank you.

Typescript support

I install this npm and i m using in my project Typescript.
Is show me this:
Could not find a declaration file for module '@vincjo/datatables'
If the '@vincjo/datatables' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module '@vincjo/datatables';

[Bug] pagination styling unresponsive after updating data

First of all: Love the tables!

I've encountered a small bug where updating the data for the table prevents the pagination to properly show what page is active.
I initiate the table with the last known data, that is in a localstorage-based store. link
The data is refreshed via an API-call using TanStack-query, and when this finished, the data in the LocalStorageStore is updated.
After this update, the visual key for the active page in the pagination does not update.

I've provided a video to illustrate the issue.

Screen.Recording.2023-08-16.at.09.18.58.mov

edit: i've noticed the same behaviour when filtering: The number of pages does not adapt, and the page-indicator does not visually update when changing pages

[Suggestion] Add internal variables such as selected & rowId

I'm wondering if it's possible to have datatables have rowId & selected as internal variables for each row.
It would certainly help with handling dynamic data that may change it's original id and also ease the burden of stapling together selection functionality.

I've poked around the source code and if I understand it correctly, it should be possible but I might be misunderstanding how it works:
The only issue I saw is how you implement rowId given the Row class is supposed to hold internal state/variables.

search with complex table-data throws errors

What fixed it for me was:
changed ca line 35 of Context.js
from

return Object.keys(row).some(k => {
  return row[k]
   .toString()
   .toLowerCase()
   .normalize("NFD")
   .replace(/[\u0300-\u036f]/g, "")
   .indexOf($globalFilter
   .toString()
   .toLowerCase()
   .normalize("NFD")
   .replace(/[\u0300-\u036f]/g, "")) > -1;
});

TO

return Object.keys(row).some(k => {
if(row[k] !== null) { 
  return row[k]
   .toString()
   .toLowerCase()
   .normalize("NFD")
   .replace(/[\u0300-\u036f]/g, "")
   .indexOf($globalFilter
   .toString()
   .toLowerCase()
   .normalize("NFD")
   .replace(/[\u0300-\u036f]/g, "")) > -1;
} else {
  return '';
}
});

is there a way to intervene witrh the search functionality? like the filter function ....

[Suggestion] Add 3rd paramter type of Object to allow sorting using returned format of getSorted()

I'm not sure if the title makes sense, but I'd like to be able to sort like the following:

handler.sort({
    identifier: 'column_name',
    direction: 'desc'
});

This is the same format as getSorted() and would allow me to pass these via the URL to the backend:

http://localhost?sort[identifier]=column_name&sort[direction]=desc

Which could be sent as a prop to the frontend so I can sort the data on page load

Is there a way to clear the filters while at the same time reseting the input or select filter?

Hello, I'm using clearFilters and while it works cleaning all the filters applied, it doesn't really reset the select for that filter. For example, after I run clearFilters function, my select still shows the selected filter (but the data change to no filter tho). I do have a wayaround this problem for now, like this:

    function clearFilters() {
        handler.clearFilters();

        document.getElementById('starred').selectedIndex = '0';
        document.getElementById('featured').selectedIndex = '0';
        document.getElementById('published_at').selectedIndex = '0';
    }

But it's extremely inefficient and it's not reusable as well since every page will have different filter. Is there any way to clear the filter while at the same time reseting any input or select that is used for that filter? Thank you.

Sorting can lead to jumping when using `setRows` to refresh data

Because the sorting only recalls the last sorted column, it can lead to rows jumping around when loading fresh data with setRows. This occurs when the most recent sorted column has many rows with identical values and previously sorting by another column. After setRows the table only recalls a single column of the sort order which may not produce the same sort as is currently displayed, causing some rows to jump. (sorry if this is a bit difficult to explain...)

You can see this in action here https://stackblitz.com/edit/vitejs-vite-xre2jw?file=src%2Flib%2FCounter.svelte

Steps:

  1. Sort by the "rest" column twice
  2. Sort by the "value" column
  3. Wait for the data to refresh and notice how the rows jump so the "rest" column changes

These steps are a bit finicky sometimes it resets from descending and sometimes from ascending. You can more easily reproduce at https://prun.josephmr.dev/orders/HLS sort by "UNITS" then wait roughly 10 seconds for the data to refresh.


I'm unsure the best method for resolving this. My main thought would be to store more than just the last column sort, but store the last N column sorts where N <= number of columns.

Feed data and pagination from backend api

Thank you for the amazing and elegant work!

My use case, involves having a headless CMS that provides api to access, paginate, filter and sort the data. The number of data rows is in the millions and hence can not be pre-fetched.

I was wondering if it is easy to connect datatables with arbitrary backend api (so the data is not all readily available) where we can retrieve the data for each page and apply any necessary filtration / sorting. All done for a backend api.

Should I, with my case above, implement/extend DataHander class?

Row selection - scope set to currentPage

Docs mention that we can set scope to currentPage,
When trying out row selection example and passing handlers selectAll method object { selectBy: "id", scope: "currentPage" } and testing it out, it seems like it is not working as expected.

Try clicking on Th checkbox and switching pages, or deselecting checkbox on single row it seems like it doesn't update as expected.

new datahandler with json object as key and embedded json arrays

Can we build a simple datatable from the json object below (with only some parts like "purchases") ?

As for now, it seems that the datahandler only accepts json arrays but not json objects.

const handler = new DataHandler(someData, { rowsPerPage: 50 })

// json example taken from https://www.customer.io/docs/json-in-segments/

someData = {
  "last_shopped": 1662587234,
  "location": {"city": "Montreal","province": "QC"},
  "purchases": [
    {
      "id": 123,
      "type": "computers",
      "name": "Monitor",
      "price": 25,
      "discount": 10,
      "shipping_address": {"city": "Calgary","province": "AB"},
      "coupons_applied": [
        {
          "coupon_code": "AXXXXX",
          "discount": "10%"
        },
        {
          "coupon_code": "BXXXXX",
          "discount": "15%"
        }
      ]
    },
    {
      "id": 456,
      "type": "computers",
      "name": "Mouse",
      "price": 15,
      "shipping_address": {"city": "Edmonton","province": "AB"}
    }
  ],
  "stores_visited": ["Winnipeg","Toronto","Vancouver"],
  "coupons_received": [5,10,20],
  "children_ages": [1654099180,1654099181,1654099182],
  "lottery_tickets":
     [
        [1,3,5,7,9],
        [1,2,3,5,8]
  ]
}

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

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.

ThFilter {handler} only filters on current page causing "undefined" error message

I have a json array with around 200 json items inside the array. Each of these json object has another lvl1 json objects defined, but it is empty ({}) if there is a not an additional lvl2 json object underneath.

I want to filter on the nested lvl2 element, and I needed to write an each block to filter out the "undefined" objects.

The global filter works fine, but when I use the column filter (rowsPerPage is set to 50), I get an undefined message.

When I browser through all possible pages first, the filtering works

Code Example

	<tr>
          <ThFilter {handler} filterBy={'lvl2'}/>
	</tr>
          </thead>
          <tbody>
              {#each $rows as row}
              <tr>
		{#if row.lvl1.lvl2?.value === undefined}
	          <td>{row.lvl2 = ""}</td>
                {:else }
                  <td>{row.lvl2 = row.lvl1.lvl2.value}</td>
		{/if}
             </tr>
            {/each}

Is there a better way to accomplish my goal to filter on nested json objects without getting an undefined error message?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.