feat(Table): add sort-mode prop

Resolves #1149
This commit is contained in:
Benjamin Canac
2024-01-09 14:54:13 +01:00
parent c6841d06a4
commit 56e0c9a9a0
3 changed files with 77 additions and 39 deletions

View File

@@ -60,5 +60,5 @@ const people = [{
</script>
<template>
<UTable :columns="columns" :rows="people" :sort="{ column: 'title' }" />
<UTable :columns="columns" :rows="people" />
</template>

View File

@@ -54,6 +54,8 @@ componentProps:
You can make the columns sortable by setting the `sortable` property to `true` in the column configuration.
You may specify the default direction of each column through the `direction` property. It can be either `asc` or `desc`, but it will default to `asc`.
::component-example{class="grid"}
---
padding: false
@@ -63,17 +65,84 @@ componentProps:
---
::
You may specify the default direction of each column through the `direction` property. It can be either `asc` or `desc`, but it will default to `asc`.
#### Default sorting
You can specify a default sort for the table through the `sort` prop. It's an object with the following properties:
- `column` - The column to sort by.
- `direction` - The sort direction. Can be either `asc` or `desc` and defaults to `asc`.
::callout{icon="i-heroicons-light-bulb"}
This will set the default sort and will work even if no column is set as `sortable`.
```vue
<script setup>
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [{
label: 'Name',
key: 'name',
sortable: true
}]
const people = [{
id: 1,
name: 'Lindsay Walton',
title: 'Front-end Developer',
email: 'lindsay.walton@example.com',
role: 'Member'
}, {
id: 2,
name: 'Courtney Henry',
title: 'Designer',
email: 'courtney.henry@example.com',
role: 'Admin'
}]
</script>
<template>
<UTable :sort="sort" :columns="columns" :rows="people" />
</template>
```
#### Reactive sorting
You can use a `v-model:sort` to make the sorting reactive. You may also use `@update:sort` to call your own function with the sorting data.
When fetching data from an API, we can take advantage of the [`useFetch`](https://nuxt.com/docs/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data) composables to fetch the data based on the sorting column and direction every time the `sort` reactive element changes.
When doing so, you might want to set the `sort-mode` prop to `manual` to disable the automatic sorting and return the rows as is. :u-badge{label="New" class="!rounded-full" variant="subtle"}
```vue
<script setup>
// Ensure it uses `ref` instead of `reactive`.
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [{
label: 'Name',
key: 'name',
sortable: true
}]
const { data, pending } = await useLazyFetch(() => `/api/users?orderBy=${sort.value.column}&order=${sort.value.direction}`)
</script>
<template>
<UTable v-model:sort="sort" :loading="pending" :columns="columns" :rows="data" sort-mode="manual" />
</template>
```
::callout{icon="i-heroicons-light-bulb" to="https://nuxt.com/docs/api/composables/use-fetch#params" target="_blank"}
We pass a function to `useLazyFetch` here make the url reactive but you can use the `query` / `params` options alongside `watch`.
::
#### Custom sorting
Use the `sort-button` prop to customize the sort button in the header. You can pass all the props of the [Button](/elements/button) component to customize it through this prop or globally through `ui.table.default.sortButton`. Its icon defaults to `i-heroicons-arrows-up-down-20-solid`.
::component-card{class="grid"}
@@ -152,41 +221,6 @@ Use the `sort-desc-icon` prop to set a different icon or change it globally in `
You can also customize the entire header cell, read more in the [Slots](#slots) section.
::
#### Reactive sorting
Sometimes you will want to fetch new data depending on the sorted column and direction. You can use the `v-model:sort` to automatically update the `ref` reactive element every time the sorting changes on the Table. You may also use `@update:sort` to call your own function with the sorting data.
For example, we can take advantage of the `useLazyFetch` computed to automatically fetch the data depending on the sorting column and direction every time the `sort` reactive element changes.
```vue
<script setup>
// Ensure it uses `ref` instead of `reactive`.
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [...]
const { data, pending } = await useLazyFetch(`/api/users?orderBy=${sort.value.column}&order=${sort.value.direction}`)
</script>
<template>
<UTable v-model:sort="sort" :loading="pending" :columns="columns" :rows="data" />
</template>
```
The initial value of `sort` will be respected as the initial sort column and direction, as well as each column default sorting direction.
::component-example{class="grid"}
---
padding: false
component: 'table-example-reactive-sorting'
componentProps:
class: 'flex-1'
---
::
### Selectable
Use a `v-model` to make the table selectable. The `v-model` will be an array of the selected rows.

View File

@@ -132,6 +132,10 @@ export default defineComponent({
type: Object as PropType<{ column: string, direction: 'asc' | 'desc' }>,
default: () => ({})
},
sortMode: {
type: String as PropType<'manual' | 'auto'>,
default: 'auto'
},
sortButton: {
type: Object as PropType<Button>,
default: () => config.default.sortButton as Button
@@ -176,7 +180,7 @@ export default defineComponent({
const savedSort = { column: sort.value.column, direction: null }
const rows = computed(() => {
if (!sort.value?.column) {
if (!sort.value?.column || props.sortMode === 'manual') {
return props.rows
}