[Runes] How to make the table content reactive?
I create a simple table component
<script lang="ts">
import { TableHandler, Datatable, ThSort, ThFilter } from '@vincjo/datatables'
let { data }: { data: any[] } = $props()
const table = new TableHandler(data, { rowsPerPage: 10 })
</script>
<Datatable basic {table}>
<table>
<thead>
<tr>
<ThSort {table} field="first_name">First Name</ThSort>
<ThSort {table} field="last_name">Last Name</ThSort>
<ThSort {table} field="email">Email</ThSort>
</tr>
<tr>
<ThFilter {table} field="first_name" />
<ThFilter {table} field="last_name" />
<ThFilter {table} field="email" />
</tr>
</thead>
<tbody>
{#each table.rows as row}
<tr>
<td>{row.first_name}</td>
<td>{row.last_name}</td>
<td>{row.email}</td>
</tr>
{/each}
</tbody>
</table>
</Datatable>
When trying to use this component:
<script lang="ts">
import Table from '$lib/components/table.svelte'
let data = $state([
{ id: 1, first_name: 'Tobie', last_name: 'Vint', email: '[email protected]' },
{ id: 2, first_name: 'Zacharias', last_name: 'Cerman', email: '[email protected]' },
{ id: 3, first_name: 'Gérianna', last_name: 'Bunn', email: '[email protected]' },
])
function addNewName() {
data.push({ id: data.length + 1, first_name: 'test', last_name: 'testlast', email: 'testmail' })
console.log('Number of data points: ' + data.length)
}
</script>
<button onclick={addNewName}>Add new name</button>
<Table {data} />
The console logs the correct number of data points, but the table is not updated with the new data.
What is the correct way of 'binding' the data to the table, so that when the data changes the table is also updated?
Small update, I can get the table to update when adding or removing items using the $effect rune but this feels quite dirty:
let table = $state(new TableHandler($state.snapshot(data)))
$effect(() => {
table = new TableHandler($state.snapshot(data), { rowsPerPage: 10 })
})
However this breaks sorting and filtering using the table headers
Yes, indeed, data must be updated using table.setRows(new_data):
The raw data is deep cloned, so no longer shares any state with the original object, even if declared as a $state rune.
Instead of data, you need to pass the TableHandler instance to your Datatable component.
Then you can apply table.setRows() in addNewName() which will update the content.
Example:
<script lang="ts">
import Table from '$lib/components/table.svelte'
import { TableHandler } from '@vincjo/datatables'
let data = [
{ id: 1, first_name: 'Tobie', last_name: 'Vint', email: '[email protected]' },
{ id: 2, first_name: 'Zacharias', last_name: 'Cerman', email: '[email protected]' },
{ id: 3, first_name: 'Gérianna', last_name: 'Bunn', email: '[email protected]' },
]
const table = new TableHandler(data, { rowsPerPage: 10 })
function addNewName() {
data.push({ id: data.length + 1, first_name: 'test', last_name: 'testlast', email: 'testmail' })
console.log('Number of data points: ' + data.length)
table.setRows(data)
}
</script>
<button onclick={addNewName}>Add new name</button>
<Table {table}/>
In your table component:
<script lang="ts">
import { type TableHandler, Datatable, ThSort, ThFilter } from '@vincjo/datatables'
let { table }: { table: TableHandler } = $props()
</script>