WtTable
Specs
Example Table
Code
vue
<script setup>
import { ref } from 'vue';
const headers = [
{
text: 'heading 1',
value: 'name',
sort: null,
},
{
text: 'heading2',
value: 'h2',
sort: null,
},
{
text: 'heading 3',
value: 'h3',
},
];
const data = ref([
{
id: 'id1',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: true,
},
{
id: 'id2',
h1: 'value 1',
h2: 'value 4',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id3',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id4',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
]);
const sort = (col, sortValue) => {
headers.forEach((header) => {
header.sort = null;
})
const column = headers.find((header) => header.value === col.value);
column.sort = sortValue;
};
const getRowClass = ({id}) => {
switch (id) {
case 'id1':
return 'row-success';
case 'id2':
return 'row-warning';
case 'id3':
return 'row-error';
default:
return '';
}
}
</script>
<template>
<wt-table
:headers="headers"
:data="data"
sortable
grid-actions
fixed-actions
resizable-columns
reorderable-columns
:row-class="getRowClass"
@sort="sort"
>
</wt-table>
</template>
<style scoped lang="scss"></style>Table with Vertical Scroll
This example demonstrates how to use wt-table with virtual scrolling for large datasets. The table automatically loads more data as you scroll down.
Code
vue
<script setup>
import { ref } from 'vue';
let index = ref(4);
const lazy = ref(true)
const loading = ref(false)
const headers = [
{
text: 'heading 1',
value: 'name',
sort: null,
},
{
text: 'heading2',
value: 'h2',
sort: null,
},
{
text: 'heading 3',
value: 'h3',
},
];
const data = ref([
{
id: 'id1',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: true,
},
{
id: 'id2',
h1: 'value 1',
h2: 'value 4',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id3',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id4',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
]);
const sort = (col, sortValue) => {
headers.forEach((header) => {
header.sort = null;
})
const column = headers.find((header) => header.value === col.value);
column.sort = sortValue;
};
const getRowClass = ({id}) => {
switch (id) {
case 'id1':
return 'row-success';
case 'id2':
return 'row-warning';
case 'id3':
return 'row-error';
default:
return '';
}
}
const onLoading = () => {
if (index.value > 50) {
return;
}
setTimeout(() => {
for (let i = 0; i < 20; i++) {
data.value.push({
id: `id${index.value}`,
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: true,
})
index.value++
}
}, 500)
}
</script>
<template>
<wt-table
class="table-scroll"
:headers="headers"
:data="data"
:lazy="lazy"
:on-loading="onLoading"
:loading="loading"
sortable
grid-actions
fixed-actions
resizable-columns
:row-class="getRowClass"
@sort="sort"
>
</wt-table>
</template>
<style scoped lang="scss">
.table-scroll {
height: 150px;
}
</style>Table with Vertical Scroll
This example demonstrates how to use wt-table with custom headers.
Code
vue
<script setup>
import { ref } from 'vue';
const headers = [
{
text: 'heading 1',
value: 'name',
sort: null,
},
{
text: 'heading2',
value: 'h2',
sort: null,
},
{
text: 'heading 3',
value: 'h3',
},
];
const data = ref([
{
id: 'id1',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: true,
},
{
id: 'id2',
h1: 'value 1',
h2: 'value 4',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id3',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
{
id: 'id4',
h1: 'value 1',
h2: 'value 2',
h3: 'value 3',
_isSelected: false,
},
]);
const sort = (col, sortValue) => {
headers.forEach((header) => {
header.sort = null;
});
const column = headers.find((header) => header.value === col.value);
column.sort = sortValue;
};
const getRowClass = ({ id }) => {
switch (id) {
case 'id1':
return 'row-success';
case 'id2':
return 'row-warning';
case 'id3':
return 'row-error';
default:
return '';
}
};
</script>
<template>
<wt-table
:headers="headers"
:data="data"
sortable
grid-actions
fixed-actions
resizable-columns
reorderable-columns
:row-class="getRowClass"
@sort="sort"
>
<template #header-name="{ header }">
custom header name: {{ header.text }}
</template>
<template #header-h2="{ header }">
custom header h2: {{ header.text }}
</template>
<template #name="{ item }">
item {{ item.id }}
</template>
</wt-table>
</template>Key Features of this Example:
- Lazy Loading: Data is loaded in chunks of 20 items as you scroll
- Virtual Scrolling: Only visible rows are rendered for better performance
- Dynamic Row Classes: Different rows have different styling based on their data
- Sorting: Click column headers to sort data
- Actions: Each row has action buttons (edit/delete)
- Fixed Height: Table has a fixed height with internal scrolling
- Loading States: Shows loading indicator during data fetch
How it Works:
- Initial Load: Starts with 4 items
- Scroll Detection: When you scroll near the bottom,
onLoadingis triggered - Data Fetch: Simulates API call with 500ms delay
- Append Data: Adds 20 new items to the existing data
- Stop Condition: Stops loading after 50 items total
Virtual Scrolling Usage:
vue
<template>
<wt-table
:headers="headers"
:data="data"
:lazy="true"
:loading="loading"
:on-loading="handleLazyLoad"
scrollable
scroll-height="150px"
sortable
grid-actions
fixed-actions
resizable-columns
:row-class="getRowClass"
@sort="handleSort"
/>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([]);
const loading = ref(false);
const lazy = ref(true);
const handleLazyLoad = () => {
if (loading.value) return;
loading.value = true;
// Simulate API call
setTimeout(() => {
// Add new data
for (let i = 0; i < 20; i++) {
data.value.push({
id: `id${index.value}`,
name: 'New Item',
// ... other properties
});
}
loading.value = false;
}, 500);
};
</script>Filter column
Код
vue
<script setup>
import { computed, reactive } from 'vue';
import ExampleColumnFilter from './example-column-filter.vue';
const priorityOptions = [
{
id: 'high',
label: 'High',
},
{
id: 'normal',
label: 'Normal',
},
{
id: 'low',
label: 'Low',
},
];
const filters = reactive({});
const headers = computed(() => [
{
text: 'Subject',
value: 'subject',
width: '280px',
},
{
text: 'Priority',
value: 'priority',
filter: 'priority',
filtered: !!filters.priority,
options: priorityOptions,
},
{
text: 'Author',
value: 'author',
filter: 'author',
filtered: !!filters.author,
},
]);
const data = [
{
id: 1,
subject: 'Payment is not going through',
priority: 'high',
author: 'Anna Shevchenko',
},
{
id: 2,
subject: 'Cannot log in to the portal',
priority: 'high',
author: 'Ihor Melnyk',
},
{
id: 3,
subject: 'Change the billing address',
priority: 'normal',
author: 'Anna Shevchenko',
},
{
id: 4,
subject: 'Request a new SIP account',
priority: 'normal',
author: 'Olena Kravets',
},
{
id: 5,
subject: 'Typo on the invoice template',
priority: 'low',
author: 'Ihor Melnyk',
},
];
const shownData = computed(() =>
data.filter((row) =>
Object.entries(filters).every(([name, value]) =>
String(row[name]).toLowerCase().includes(String(value).toLowerCase()),
),
),
);
const addFilter = ({ name, value }) => {
filters[name] = value;
};
const deleteFilter = ({ name }) => {
delete filters[name];
};
</script>
<template>
<wt-table
:headers="headers"
:data="shownData"
>
<template #column-filter="{ header, formView, hide }">
<example-column-filter
:header="header"
:form-view="formView"
:hide="hide"
:value="filters[header.value] || ''"
@apply="addFilter"
@clear="deleteFilter"
/>
</template>
</wt-table>
</template>
<style scoped lang="scss"></style>vue
<script setup>
import { ref } from 'vue';
const props = defineProps({
header: {
type: Object,
required: true,
},
formView: {
type: Boolean,
default: false,
},
hide: {
type: Function,
default: null,
},
value: {
type: String,
default: '',
},
});
const emit = defineEmits([
'apply',
'clear',
]);
const draft = ref(props.value);
const apply = () => {
emit('apply', {
name: props.header.value,
value: draft.value,
});
props.hide?.();
};
const clear = () => {
draft.value = '';
emit('clear', {
name: props.header.value,
});
props.hide?.();
};
</script>
<template>
<!-- vp-raw: попап телепортується в body, і без нього VitePress скидає стилі кнопок -->
<div
v-if="!formView"
class="example-column-filter-preview vp-raw"
>
<p class="typo-body-2-bold">{{ header.text }}</p>
<p class="typo-body-2">{{ value }}</p>
</div>
<form
v-else
class="example-column-filter vp-raw"
@submit.prevent="apply"
>
<wt-single-select
v-if="header.options"
v-model="draft"
:options="header.options"
:label="header.text"
option-value="id"
/>
<wt-input-text
v-else
v-model="draft"
:label="header.text"
/>
<footer class="example-column-filter__footer">
<wt-button
:disabled="!draft"
wide
@click="apply"
>
Apply
</wt-button>
<wt-button
color="secondary"
wide
@click="clear"
>
Clear
</wt-button>
</footer>
</form>
</template>
<style scoped lang="scss">
.example-column-filter {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
box-sizing: border-box;
width: 280px;
}
.example-column-filter__footer {
display: flex;
gap: var(--spacing-xs);
}
.example-column-filter-preview {
display: flex;
flex-direction: column;
gap: var(--spacing-3xs);
}
</style>TIP
У таблиці на @webitel/ui-datalist цей компонент писати не треба — ColumnFilterComponent уже робить це поверх filtersManager вашого table store. Див. ui-datalist: Фільтри.