bryanmylee / svelte-headless-table Goto Github PK
View Code? Open in Web Editor NEWUnopinionated and extensible data tables for Svelte
Home Page: https://svelte-headless-table.bryanmylee.com/
Unopinionated and extensible data tables for Svelte
Home Page: https://svelte-headless-table.bryanmylee.com/
Writing true
to the allPageRowsSelected
store adds only the current page's IDs to the selectedDataIds
store, as expected.
But setting it to false
clears all selected rows, not only the ones on the current page.
I would expect the behavior to be consistent where setting true and false add/remove current page IDs only.
Relevant code in addSelectedRows.ts
const setAllPageRowsSelected = ($allPageRowsSelected: boolean) => {
if ($allPageRowsSelected) {
const $pageRows = get(tableState.pageRows);
const pageDataIds = $pageRows
.map((row) => (row.isData() ? row.dataId : null))
.filter(nonNull);
selectedDataIds.addAll(pageDataIds);
} else {
selectedDataIds.clear();
}
};
I have this code which worked perfectly except the Edit button
const repository = new UserRepository()
const data: Readable<User[]> = readable([], function start(set: Subscriber<User[]>) {
return repository.listenAll(users => set(users ?? []))
})
const table = createTable(data)
const columns = table.createColumns([
table.column({
header: 'Username',
accessor: 'username'
}),
table.column({
id: 'actions',
header: 'Actions',
accessor: (item) => item,
cell: ({value}, state) => createRender(TableActions)
.on('edit', () => console.log(value.username))
})
])
When a user click on edit button inside TableActions component, it'll trigger the edit
event. The problem is when data changes, the username that gets printed on the console is not changed, it always printed the old value unless I refresh the page.
Workaround
cell: (cell, state) => createRender(TableActions)
.on('edit', () => console.log(get(state.data)[cell.row.id].username))
Really enjoying working with svelte-headless-table so far! It would be great if we could add an example on how to conditionally apply styles to individual rows/columns/cells. E.g. append a style to the first column and all rows under <tbody>
From the example I can see this gets applied by:
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
<tr {...rowAttrs}>
Can we include an example of how you'd pass values into rowAttrs
from table.createColumns
?
Thanks
So I'm preprocessing my data, and adding in a invalid: (predicate result)
key on my object, I'd like to style the "invalid" rows to have a red background color, I tried:
<Subscribe
attrs={row.attrs()}
let:attrs
props={row.props()}
let:props
>
<tr
{...attrs}
class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"
class:invalid={props.} // intellisense won't show my my original object here
>
but props
won't let me access the "invalid" key, same with attrs
First of all - I am probably doing this the wrong way, so please enlighten me.
I would like to have custom header cell, so I guess I have three ways to do it
{#each headerRow.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} props={cell.props()} let:attrs let:props>
<div {...attrs}>
// render my custom component like this
<Render of={cell.render()}/>
// or just use plain html
<span>{cell.label}</span>
// or svelte component
<MyCustomHeader {cell}/>
</div>
</Subscribe>
{/each}
Looking at the docs, you are recommending to use createRender
tho. Why is Render
recommended ? If we want to enable the sorting plugin, we are adding plain html anyway, right ?
{#each headerRow.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} props={cell.props()} let:attrs let:props>
<div {...attrs}>
<Render of={cell.render()}/>
// from the example
{#if props.sort.order === 'asc'}
⬇️
{:else if props.sort.order === 'desc'}
⬆️
{/if}
</div>
</Subscribe>
{/each}
If I want to have that sorting "hidden" in the header cell component, I need to do this kind of thing, since header
does not provide the specific HeaderCell
but the whole table state.
table.column({
header: (state) => {
return createRender(TableHeaderCell, {
label: "Popis",
sortToggle: () => state.pluginStates.sort.sortKeys.toggleId("description", {}),
sortOrder: get(state.pluginStates.sort.sortKeys).find(key => key.id === "description")?.order
})
},
accessor: "description",
}),
I feel like I am doing something horribly wrong. Would you mind explaining please ?
The ability to resize columns breaks if you subscribe to the main data store more than once in separate functions and don't also implement the addHiddenColumns plugin.
Here is an example in a REPL:
https://svelte.dev/repl/71eb58bfe8754460926531cf211405da?version=3.49.0
Details:
The REPL above is a clone of the 'Simple Column Resizing' REPL. The only difference is it adds two functions.
function read1() {
console.log($data[0])
}
function read2() {
console.log($data[1])
}
Just adding those functions completely breaks the resizing of columns. The functions don't even have to be called. I haven't yet figured out what causes them to break the resizing; though, I assume it has to do with how Svelte Headless Table manages the state of the resizing columns.
By adding and implementing the addHiddenColumns plugin, the columns will resume resizing as expected.
Here is an example in a REPL:
https://svelte.dev/repl/9c2868beb9ef4c0897ccdcab0dbfcda4?version=3.49.0
This is the code that has to be added:
import { addHiddenColumns, addResizedColumns } from 'svelte-headless-table/plugins';
const table = createTable(data, {
hideColumns: addHiddenColumns(),
resize: addResizedColumns(),
});
const {
flatColumns,
headerRows,
pageRows,
tableAttrs,
tableBodyAttrs,
visibleColumns,
pluginStates,
} = table.createViewModel(columns);
const ids = flatColumns.map((c) => c.id);
const { hiddenColumnIds } = pluginStates.hideColumns;
let hideForId = Object.fromEntries(ids.map((id) => [id, false]));
$: $hiddenColumnIds = Object.entries(hideForId)
.filter(([, hide]) => hide)
.map(([id]) => id);
At least on REPL examples and my environment, sorting doesn't seem to work when clicked on the columns. Not sure if it affects other things as I just started trying things out.
https://svelte.dev/repl/457c10b649cc4bc7a84f9511a81b5361?version=3.48.0
Downgrading to 0.16.2 does make it work on my environment.
If any transformations before the column filter removes all values of a distinct class, then the SelectFilter component does not see all possible options.
Ideally, we should be able to expose the originalRows to the SelectFilter / filter plugin.
Hi,
I am aware that we already have pagination plugin in place which works great, but would it be possible to add an "infinite virtual list" pagination plugin ?
The idea would be to limit the table height and specify (or auto-calculate if reasonable) how many items will be shown/rendered and the rendered offset would be managed by scroll, eg. infinite virtual scroll.
Maybe this would be possible to "plug-in" ? https://github.com/Skayo/svelte-tiny-virtual-list
Hi there!
I'm trying to use this component in an app of mine.
It's using svelte-i18n
, and for a vanilla table I put stuff like: <th>{$_('name')}</th>
into the svelte template section for my table headers. This automatically changes when the language is switched.
Now to get started with your library, I've copied the code from your quick-start sample into a new Svelte component, and added those imports:
import { _ } from "svelte-i18n";
import {createTable, Subscribe, Render} from 'svelte-headless-table';
import { readable } from "svelte/store";
(it would be nice if you could copy the ones everybody needs into your sample, so future users don't need to search for them themselves, see pull request)
Anyway, now in the column definition, I replaced header: 'name'
with header: $_('name')
- which works, but isn't reactive, so doesn't change when the language changes.
How can I go about doing this in a way that preserves / propagates the reactivity?
I'm using Supabase to query data to load into a table but I keep getting this error: Cannot read properties of undefined (reading 'map')
Data Model
[
{
"name": "Partner",
"permissions": [
{
"can_add_members": false,
"can_delete_members": false,
"can_edit_members": false,
"can_create_roles": false,
"can_delete_roles": false,
"can_edit_roles": false,
"can_assign_roles": false,
"can_create_projects": false,
"can_delete_projects": false,
"can_edit_projects": false,
"can_publish_projects": false,
"can_view_projects": false,
"can_assign_members_to_projects": false
}
]
},
{
"name": "Associate Partner",
"permissions": [
{
"can_add_members": false,
"can_delete_members": false,
"can_edit_members": false,
"can_create_roles": false,
"can_delete_roles": false,
"can_edit_roles": false,
"can_assign_roles": false,
"can_create_projects": false,
"can_delete_projects": false,
"can_edit_projects": false,
"can_publish_projects": false,
"can_view_projects": false,
"can_assign_members_to_projects": false
}
]
},
{
]
Code
const roleArray = writable([])
onMount(() => {
getPermissions()
});
// TABLE CODE
const table = createTable(roleArray);
const columns = table.createColumns([
table.column({
header: 'Name',
accessor: 'name',
}),
]);
const {
headerRows,
rows,
tableAttrs,
tableBodyAttrs,
} = table.createViewModel(columns);
// GET PERMISSIONS FROM SUPABSE
async function getPermissions(){
const { data: firm, error } = await supabaseClient
.from('firms')
.select('role_permissions')
.eq('id',$userOrgID)
if (firm){
// console.log(JSON.stringify(firm, null, 2))
const [fetchedUser] = firm;
//console.log(fetchedUser.role_permissions)
roleArray.set(fetchedUser.role_permissions)
console.log($roleArray)
} else{
console.log("Error fetching permissions", error)
}
}
Hi!
I'm using this library to perform research on big tables and I figure out that the filter doesn't filter pieces of worlds. Like if I have a value like "Computer science" and I try to filter "science" I will not see that row, I can only see it if I search "computer".
I think that can be useful to change this or allow the option to choose between this way to do the filter and the one that I proposed.
Would it be possible to expose an event after resizing a table header? The use case would be for storing $columnWidths to localStorage, so the client does not need to resize their table columns every time. Currently I am calling the function with on:mouseup from the thead, but this is unreliable ie if the user drags the mouse up away from the table while resizing.
Thanks for the great library.
Currently, row ids are generated based on position in the original data.
To support better row selection and other row-id related plugins, we should allow developers to define their own id accessors.
Allow developers to annotate BodyRows with a custom component that spans the entire row.
It should receive the row's original item as a prop to produce a RenderConfig
.
Awesome tool!
Trying to integrate it with the table module used in 'svelte-gantt' (https://github.com/ANovokmet/svelte-gantt/tree/master/src/modules/table). My point of struggle is that headless table doesn't seem to provide an object that reflects the 'displayed state' of the data in the table (sort -> with sorted items, grouping -> with switched children/parents). Any ideas how to derive that?
Example for sorting (e.g. item 0 in table is item 3 in object):
Linked comment.
Currently, the creation of the view model is done with useTable
and all plugins are prefixed with useX
. This is primary influenced by React Table, but this might lead beginners to confuse the functions with Svelte actions and the use directive.
useTable
useTable
should be renamed. Some ideas considered are:
createTableViewModel
– this is the most descriptive but might be a little wordy.createViewModel
– this is too generic and does not indicate any relevance to Svelte Headless Table.table.createViewModel
– alternatively, we could re-export the function as a property on table
.const { headerRows, rows } = table.createViewModel(columns)
Currently, the plugins are prefixed with use
to indicate that the functions are meant to be used on the table. Some alternatives considered are:
use
prefix entirely – this would be the most succinct, but we lose out on the standard prefix to identify the plugins.We also run into an issue of confusing property and function names. The keys for plugin names should describe what they are e.g. sort
, filter
, group
, while the plugin functions should describe what they do. By removing the prefix, we potentially end up with names such as tableFilter: tableFilter()
. While this is clear to most JS/TS users, the similarities to property shorthand notation may be confusing to beginners.
const table = createTable(data, {
sort: sortBy(),
tableFilter: tableFilter(),
filter: columnFilters(),
});
applyX
– it might be an extra two characters but this could achieve most of what we want without adding any confusion with the use directive.const table = createTable(data, {
sort: applySortBy(),
tableFilter: applyTableFilter(),
filter: applyColumnFilters(),
});
Hi, really enjoying this project, thanks for developing and maintaining it!
Is there any reccomended way of virtualising the tables generated? I know this is not really a concern of the library, but maybe it could become one?
Hi,
I'd like to request the following feature(s):
Illustrating Picture (edited):
Illustrating REPL (Basis for the picture):
https://svelte.dev/repl/320d8a80589a4c34950e335ae377f60f?version=3.50.1
Reason:
I want the table to describe the 'natural structure of a product' (consisting of different parts as children or even grand children).
However I want to be 'able to change the score' quickly to only look at child layers (e.g. part level).
I hope you can understand what I mean (:
Allow data items to specify sub-items and render them as subrows.
The column model will also need to be extended to allow for DisplayColumn
s that do not represent any data property, but represents additional UI for row expansion state etc.
from the example, I see that it just hides the same dataset, but what if I want to load an entirely different object array
This will mostly be for server-side managed pagination.
This is related to #20.
Moving forward, when providing more layout options, it is not always guaranteed that data cells will adopt their width from their column header cells.
To provide more flexibility, addResizedColumns
should provide an option to set the width of all elements explicitly.
Right now it's painful to work with cell events.
I have a situation, where my table row last column is an "action" column with bunch of buttons (eg. edit, delete) and I would like to listen to the dispatched event from the cell right at the table component or even outside of it to process it and modify the table data.
The Render
component now blocks custom events and using solution in #45 seems kind of dirty.
I need to dynamically listen to my unknown list of actions (row A can have one action, row B three and row C won't have any)
I think some simple table event system would be great - dispatch event which would automaticaly include the current cell and my custom data.
Example at my custom cell
<script>
export let dispatchTableEvent // provided by this library, equivalent of `createEventDispatcher()` output
const handleMyEvent = () => {
dispatchTableEvent("my_event", {
my_custom_payload: "world",
})
}
</script>
<button on:click|preventDefault={handleMyEvent}>
HELLO
</button>
Example at table definition
const { events } = table.createViewModel(columns)
// or events.on()
events.addListener("my_event", (e) =>{
e.detail.cell // dispatched DataCell object
e.detail.my_custom_payload // any other payload I defined
})
// or make it universal
events.any((e) =>{
// handle any dynamic event type
})
I am aware that I can make this system myself as a separate thing or perhaps as a plugin (I am not sure how would I go around adding custom props to each cell - the event dispatcher), but it would be nice to have it build in.
Would that be considered as a "bloat" that user can do himself and you would rarther have cleaner/simpler package ?
Ok so, no matter what I try, sortBy
just won't work, I copied the simple example, but when I use the same example on my local machine, sorting just won't work, any ideas? I'm not getting any errors whatsoever, that's why I can't diagnose the issue
package.json
:
"devDependencies": {
"@babel/core": "^7.14.0",
"@babel/preset-env": "^7.14.0",
"@hurtigruten/svelte-table": "^2.0.3",
"@iconify/svelte": "^2.2.1",
"@sveltejs/adapter-static": "^1.0.0-next.26",
"@sveltejs/kit": "next",
"@testing-library/jest-dom": "^5.14.0",
"@testing-library/svelte": "^3.0.0",
"@types/jest": "^27.0.0",
"@types/testing-library__jest-dom": "^5.14.0",
"autoprefixer": "10.4.5",
"babel-jest": "^27.0.0",
"cross-env": "^7.0.3",
"date-picker-svelte": "^2.0.0",
"flowbite": "^1.4.5",
"flowbite-svelte": "^0.17.3",
"jest": "^27.0.0",
"jspdf": "^2.5.1",
"n2words": "^1.11.1",
"postcss": "^8.4.12",
"postcss-load-config": "^3.1.4",
"svelte": "^3.44.0",
"svelte-check": "^2.2.6",
"svelte-headless-table": "^0.10.2",
"svelte-jester": "^2.0.1",
"svelte-preprocess": "^4.9.4",
"svelte-typeahead": "^4.2.2",
"tailwindcss": "^3.0.23",
"ts-jest": "^27.0.0",
"tslib": "^2.3.1",
"typescript": "^4.6.2",
"wretch": "^1.7.9",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.18.9/xlsx-0.18.9.tgz"
},
svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess({ postcss: true }),
kit: {
adapter: adapter(),
// Apply the proxy setup
vite: () => ({
server,
optimizeDeps: {
include: ['fuzzy'],
},
}),
},
};
export default config;
Originally posted by @Gildedter in #28 (comment)
Hi :)
I noticed that the plugin does not seem to output parent/ child hierarchy correctly when choosing type 'object':
Expected behaviour in this case would be the that there are 2 top level objects instead of 6, when expanded.
Example RPL
In case the error is on my end.. please give me a hint.
Your awesome work is very much appreciated!
This is probably my favourite Svelte libraries, it's so useful and versatile! Thank you so much for making this.
I do have one small gripe, which is that there isn't a "select all" option for the addSelectedRows
plugin. This can be hacked in like so:
// on init
let tableColumns = [];
let selectAll = writable(false);
if (selectable) {
tableColumns.push(table.display({
id: 'selected',
header: () => createRender(Checkbox, { // renders the "select all"
isSelected: selectAll
}),
cell: ({ row }, { pluginStates }) => {
const { isSelected } = pluginStates.select.getRowState(row);
return createRender(Checkbox, {
isSelected
});
},
plugins: {
sort: {
disable: true
}
}
}));
}
// ... continue initialising columns
and then subscribing to the newly created selectAll
to cascade the changes to all other checkboxes:
const { selectedDataIds } = pluginStates.select;
if (selectable) {
selectAll.subscribe(val => {
if (!val) selectedDataIds.clear();
else {
let rows = $pageRows;
let newSelected = {};
for (const row of rows) {
newSelected[row.id] = true;
}
$selectedDataIds = { ...newSelected };
}
});
}
This works fine, but could run in to issues when trying to do things the other way around - ie. trying to select the "select all" option when all rows are selected. You could probably do something like:
selectedDataIds.subscribe(val => {
if (val.length !== $pageRows.length) return;
let newValue = true;
for (const rowVal of val) {
if (!rowVal) {
newValue = false;
break; // exit early
}
}
$selectAll = newValue;
});
But you may run in to issues w/ constantly cascading changes between the 2 subscribe
functions.
It'd be nice if there was a sane default for a select all option, especially if it were performant - I'm not too worried about the performance of the library, but for my use case actually these headless tables take up the bulk of the application so I do get slightly wary about having to implement some of these things.
Thanks again for the library, however, it's saved me countless hours over the last month (and will continue to do so)!
Hello, is it possible to filter the columns so that ANY matches are displayed? For example, in the docs simple filtering example, if status was single OR first name was Cordia.
Thank you!
Not sure how to read an event while using createRender. I have a dropdown menu which I could render like below
<UserActionsDropdown on:message={handleMessage}/>
I want to dispatch an event from UserActionsDropdown and be able to handle in the table below. How would be possible?
table.column({
header: '',
id: 'selected',
accessor: (item) => item,
cell: ({ value }) => {
return createRender(UserActionsDropdown, {
userId: value.id
});
}
})
Ideally, it should expose update
and set
methods on the view model extensions for BodyCells to allow for easier updates.
It should also provide a callback / event listener for handling edits with more control.
It should also provide methods on the view model extensions to confirm / cancel edits.
Multi-editing can be a configuration option.
We could provide plugin state to the developer without transforming the rows.
Plugin state can then be used to signal the server for changes to data
.
I just tried and fall in love with this library, thanks a lot.
I want suggestion or to discuss on how to implement editable-table
better.
This is my REPL implementation, which feel like a hacky way.
store
(Writable
) is in its own file and is imported by Table
and Input
componentInput
has 3 props: value
, rowId
and columnId
cell
use createRender
to render Input
and pass all props
to Input
componentInput
component then access store
with $store
and set value with $store[rowId][columnId] = value
Edit:
Current problem
row
and column
to use in Input
component$store[rowId][columnId]
is the best way or should there be an alternative way.Feature request mentioned in #51.
Hi, I have just added your package and tried to create a very basic table as listed in the docs and I am getting error when my accessor
is an function. Am I missing something ?
Uncaught (in promise) Error: A column id or string accessor is required
const data = writable([
{
id: "t1",
description: "dsajk hskf alfgb akl asklfal fba",
supplier: {
id: "sup1",
name: "supplier test",
},
amount: "2",
unitOfMeasure: "ks",
attachment: {
id: "attachment1",
name: "aaa aaaa aa aaaaa aaa.jpg",
},
},
])
const table = createTable(data)
const columns = table.createColumns([
table.column({
header: "Popis",
accessor: "description",
}),
table.column({
header: "Dodavatel",
accessor: (item) => item.supplier.name, // <-- it fails here
}),
table.column({
header: "Množství",
accessor: "amount",
}),
table.column({
header: "Měrná jednotka",
accessor: "unitOfMeasure",
}),
])
Just something like ,
createRender('div', {class: 'i-ic:iconname' })
render div with classname like <svelte:element this="div"> do.
Svelte kit Version: 1.0.1
Svelte version: 3.55.0
I copied the quick start code into a component and included that in a +page.svelte file.
I get the error cannot read properties of undefined (reading 'createTable'). When I followed the guide I altered it to suit my needs and that errored with "tableAttrs is not defined"
Is this a version issue? Or vite optimizing the module?
Thanks.
Is any plugin to add click event to each row with its corresponding data as argument?
Hi,
I noticed the following issue when combining the two mentioned plugins on nested data:
Example REPL:
https://svelte.dev/repl/320d8a80589a4c34950e335ae377f60f?version=3.50.1
In case that I overlooked something please give me a hint, thank you! (:
Title
usePagination paginates the table by transforming rows and producing a resulting row set that represents the page. However, the resulting row set should not represent the number of rows in the table.
This poses an issue when previous plugins or column definitions subscribe to TableState#rows
. For example, a header render config might subscribe to TableState#rows
to display the number of items in the table via TableState#rows.length
. We expect TableState#rows.length
to decrease if a filtering plugin is used i.e. useColumnFilters
or useFilters
. However, usePagination
should not have an effect on TableState#rows.length
.
page
pluginState on usePagination
React Table takes the approach of adding a new page
property on the table instance which does not affect rows
, and directs users to use page
to display the page instead. This allows TableState#rows
to remain unaffected. We could recreate this by exposing a page
store on usePagination
's pluginState
.
However, the plugin architecture at the moment does not allow for the table's full plugin definitions or types to be passed into individual plugins. This is related to a more general issue where plugins are processed in sequence; a plugin cannot access the state of plugins defined after it. As a result, we lose out on type definitions on any BodyRow
stores accessed from pluginState
.
Another issue is the loss of plugin state, prop sets, and attributes on table components accessed from pluginState
. Plugin state and prop sets are only injected into the final transformed headers and rows to reduce the number of subscribers to each plugin's state. If we allow table components to be defined in pluginState
, we would have to forgo this optimization. However, more work needs to be done to determine if this optimization is unnecessary.
One more issue with the current architecture is how pre-X
rows are currently implemented. All pre-X
rows are empty when initialized, and only set if the original rows
property is accessed; pre-X
rows are only set when deriveRows
is called.
deriveRows
and derivePage
We already define intrinsic structural properties for table components, and plan on adding more (e.g. children
for row aggregation and expansion). It isn't entirely out of the picture to define derivePage
as an intrinsic function on useTable
much like deriveRows
and deriveFlatColumns
are. This would also be re-used when useTokenPagination
is implemented.
Although this reduces the flexibility of the plugin system, it may be an acceptable compromise. Mandating more structure for the plugin system should reduce the complexity of the mental model and reduce any unwanted side effects.
Awesome work, currently exploring the possibilities!
Noticed the following issue:
Properties expanded and selected of $exportedData remain 'null' although rows are expanded/ selected.
Example REPL:
https://svelte.dev/repl/6252bf57d8c64a59bd347e311241ebf2?version=3.48.0
I am still quite new to svelte so maybe the error is on my side. I'd be greatful for a hint in that case.
Hello,
I would like to add animations to my rows so that for example the sorting is nicely animated.
Right now I would need to remove <Subscribe>
component hosting the table row tr
<tbody {...$tableBodyAttrs}>
{#each $rows as row (row.id)}
// <Subscribe rowAttrs={row.attrs()} let:rowAttrs>
<tr animate:flip={{delay: 0, duration: 200, easing: quintInOut}} class="group text-sm" {...row.attrs()}>
{#each row.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} let:attrs>
<td class="group-hover:bg-neutral-100 px-4 first:pl-8 last:pr-4 py-2.5" {...attrs}>
<Render of={cell.render()}/>
</td>
</Subscribe>
{/each}
</tr>
// </Subscribe>
{/each}
</tbody>
Is it even possible to achieve animations with the Subscribe
component wrapping our tr
row ?
On the other hand what exactly are we losing (and how critical it is) when we remove the Subscribe
component ?
One of the things this library is missing (but could probably add reasonably easily - he says...) is the ability to add what I will call "high level" table filters.
In short, these would be moreso "descriptive" filters that don't align with a specific column or existing filter. As an example, a high level filter may be:
name: High Value
filter: row => row.value > 700 && row.status !== 'refunded'
The idea is that you could apply many high level filters, acting as either an AND or an OR. These could be toggled at any time dynamically changing the available rows for export, viewing etc.
API examples
// sidenote: could either have an extra "name" field, or use "key" as the "name" AND the key
createTable(data, {
highLevelFilters: addHighLevelFilters({
method: 'AND', //AND, OR
filters: [
{
key: 'high-value',
fn: row => row.value > 700 && row.status !== 'refunded'
},
{
key: 'low-value',
fn: row => row.value < 700 && row.status !== 'refunded'
},
{
key: 'recent',
fn: row => row.date >= new Date((new Date().getDate()) - 7) //not _technically_ correct but just as an example
}
])
});
// ... getting filters
const { appliedFilters, filterMethod, availableFilters } = pluginStates.highLevelFilters;
// ... toggle filter
appliedFilters.toggle('high-value');
// ... add filter
appliedFilters.add('high-value');
// ... remove filter
appliedFilters.remove('high-value');
// ... set filter method
$filterMethod = 'OR';
// ... render available filters
{#each $availableFilters as filter }
<button on:click={() => appliedFilters.toggle(filter.key)}>toggle {filter.key}</button>
{/each}
Not sure how you would feel about something like this, but at least for my use case it'd be super helpful.
I can probably contribute this myself but I'm really not that great with TypeScript so might need someone to jump in and type-ify it for me.
I had some issues using the headless-table in a current SvelteKit project using PNPM.
I got it running after installing
But there was no error that pointed to that solution.
Additionally I have a problem with typings. Importing the package in a svelte component with the lang="ts" attribute says
Could not find a declaration file for module 'svelte-headless-table'
Any ideas how to fix that? Thank you!
Would be great of documentation had a "search" feature.
Hi, this library is awesome, thanks for putting it together and sharing it!
Is there a shortcut approach to "exporting" the current Table state as a JSON collection? With all sorting and filters applied, and col state (hidden), derived cols, and col names as keys, etc?
If not, then any advice on how best to hit the API to construct a custom renderJSON() for the Table? Or just brute force it? ;-)
Scientific apps I build tend to require dumping table state as csv files, which I typically do from JSON collections created from stores and applied app state.
Many thanks!
-Larry
This plugin should expose view model extensions to allow for easy drag-to-resize controls to resize columns.
It should also provide column options to size by px
or %
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.