Improve DataTable demo performance

pull/5018/head
mertsincan 2023-12-31 14:08:33 +00:00
parent 69d9c0875b
commit 27db388223
48 changed files with 1560 additions and 1366 deletions

View File

@ -0,0 +1,55 @@
<template>
<div v-if="!visible" class="demo-section-loading">Loading...</div>
<slot v-else></slot>
</template>
<script>
export default {
name: 'DeferredDemo',
emits: ['load'],
props: {
options: {
type: Object,
default: null
}
},
data() {
return {
visible: false
};
},
observer: null,
timeout: null,
mounted() {
this.observer = new IntersectionObserver(([entry]) => {
clearTimeout(this.timeout);
if (entry.isIntersecting) {
this.timeout = setTimeout(() => {
this.visible = true;
this.observer.unobserve(this.$el);
this.$emit('load');
}, 350);
}
}, this.options);
this.observer.observe(this.$el);
},
beforeUnmount() {
!this.visible && this.$el && this.observer?.unobserve(this.$el);
clearTimeout(this.timeout);
}
};
</script>
<style>
.demo-section-loading {
display: grid;
place-items: center;
padding: 2rem;
border-radius: 10px;
margin-bottom: 1rem;
font-size: 2rem;
height: 350px;
background: var(--maskbg);
}
</style>

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>DataTable requires a <i>value</i> as data to display and <i>Column</i> components as children for the representation.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,50 +5,52 @@
to span are defined with the <i>colspan</i> and <i>rowspan</i> properties of a Column.
</p>
</DocSectionText>
<div class="card">
<DataTable :value="sales" tableStyle="min-width: 50rem">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" sortable field="lastYearSale" />
<Column header="This Year" sortable field="thisYearSale" />
<Column header="Last Year" sortable field="lastYearProfit" />
<Column header="This Year" sortable field="thisYearProfit" />
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.lastYearProfit) }}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.thisYearProfit) }}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right" />
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="sales" tableStyle="min-width: 50rem">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" sortable field="lastYearSale" />
<Column header="This Year" sortable field="thisYearSale" />
<Column header="Last Year" sortable field="lastYearProfit" />
<Column header="This Year" sortable field="thisYearProfit" />
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.lastYearProfit) }}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.thisYearProfit) }}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right" />
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" />
</template>
@ -294,21 +296,21 @@ const thisYearTotal = computed(() => {
}
};
},
created() {
this.sales = [
{ product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342 },
{ product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122 },
{ product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500 },
{ product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323 },
{ product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332 },
{ product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005 },
{ product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214 },
{ product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322 },
{ product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232 },
{ product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533 }
];
},
methods: {
loadDemoData() {
this.sales = [
{ product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342 },
{ product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122 },
{ product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500 },
{ product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323 },
{ product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332 },
{ product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005 },
{ product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214 },
{ product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322 },
{ product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232 },
{ product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533 }
];
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}

View File

@ -2,17 +2,19 @@
<DocSectionText v-bind="$attrs">
<p>Column visibility based on a condition can be implemented with dynamic columns, in this sample a MultiSelect is used to manage the visible columns.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align: left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle" display="chip" placeholder="Select Columns" />
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :key="col.field + '_' + index" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align: left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle" display="chip" placeholder="Select Columns" />
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :key="col.field + '_' + index" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -30,7 +32,7 @@ export default {
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align:left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
display="chip" placeholder="Select Columns" />
</div>
</template>
@ -44,7 +46,7 @@ export default {
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align:left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
display="chip" placeholder="Select Columns" />
</div>
</template>
@ -139,7 +141,6 @@ const onToggle = (val) => {
}
};
},
created() {
this.columns = [
{ field: 'name', header: 'Name' },
@ -148,10 +149,10 @@ const onToggle = (val) => {
];
this.selectedColumns = this.columns;
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onToggle(value) {
this.selectedColumns = this.columns.filter((col) => value.includes(col));
}

View File

@ -2,20 +2,22 @@
<DocSectionText v-bind="$attrs">
<p>Particular rows and cells can be styled based on conditions. The <i>rowClass</i> receives a row data as a parameter to return a style class for a row whereas cells are customized using the <i>body</i> template.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" :rowClass="rowClass" :rowStyle="rowStyle" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{ slotProps.data.quantity }}
</div>
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" :rowClass="rowClass" :rowStyle="rowStyle" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{ slotProps.data.quantity }}
</div>
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -119,7 +121,7 @@ import { ProductService } from '@/service/ProductService';
onMounted(() => {
ProductService.getProductsSmall().then((data) => (this.products = data));
});
const products = ref();
const rowClass = (data) => {
@ -160,10 +162,10 @@ const stockClass = (data) => {
}
};
},
mounted() {
ProductService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsSmall().then((data) => (this.products = data));
},
rowClass(data) {
return [{ 'bg-primary': data.category === 'Fitness' }];
},

View File

@ -4,19 +4,21 @@
DataTable has exclusive integration with ContextMenu using the <i>contextMenu</i> event to open a menu on right click alont with <i>contextMenuSelection</i> property and <i>row-contextmenu</i> event to control the selection via the menu.
</p>
</DocSectionText>
<div class="card">
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" />
<DataTable v-model:contextMenuSelection="selectedProduct" :value="products" contextMenu @row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" />
<DataTable v-model:contextMenuSelection="selectedProduct" :value="products" contextMenu @row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -51,7 +53,7 @@ export default {
<template>
<div class="card">
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" />
<DataTable :value="products" contextMenu v-model:contextMenuSelection="selectedProduct"
<DataTable :value="products" contextMenu v-model:contextMenuSelection="selectedProduct"
@rowContextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
@ -174,10 +176,10 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowContextMenu(event) {
this.$refs.cm.show(event.originalEvent);
},

View File

@ -2,11 +2,13 @@
<DocSectionText v-bind="$attrs">
<p>Columns can be created programmatically.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -110,8 +112,10 @@ const columns = [
{ field: 'quantity', header: 'Quantity' }
];
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,19 +2,21 @@
<DocSectionText v-bind="$attrs">
<p>DataTable can export its data to CSV format.</p>
</DocSectionText>
<div class="card">
<DataTable ref="dt" :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align: left">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable ref="dt" :value="products" tableStyle="min-width: 50rem">
<template #header>
<div style="text-align: left">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -127,10 +129,10 @@ const exportCSV = () => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
exportCSV() {
this.$refs.dt.exportCSV();
}

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Enabling <i>showGridlines</i> displays borders between cells.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -10,65 +10,67 @@
</p>
<p>Note that, the implementation of <i>checkbox selection</i> in lazy mode needs to be handled manually as in this example since the DataTable cannot know about the whole dataset.</p>
</DocSectionText>
<div class="card p-fluid">
<DataTable
ref="dt"
v-model:filters="filters"
v-model:selection="selectedCustomers"
:value="customers"
lazy
paginator
:first="first"
:rows="10"
dataKey="id"
:totalRecords="totalRecords"
:loading="loading"
@page="onPage($event)"
@sort="onSort($event)"
@filter="onFilter($event)"
filterDisplay="row"
:globalFilterFields="['name', 'country.name', 'company', 'representative.name']"
:selectAll="selectAll"
@select-all-change="onSelectAllChange"
@row-select="onRowSelect"
@row-unselect="onRowUnselect"
tableStyle="min-width: 75rem"
>
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name" filterMatchMode="startsWith" sortable>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="country.name" header="Country" filterField="country.name" filterMatchMode="contains" sortable>
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="company" header="Company" filterMatchMode="contains" sortable>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="representative.name" header="Representative" filterField="representative.name" sortable>
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card p-fluid">
<DataTable
ref="dt"
v-model:filters="filters"
v-model:selection="selectedCustomers"
:value="customers"
lazy
paginator
:first="first"
:rows="10"
dataKey="id"
:totalRecords="totalRecords"
:loading="loading"
@page="onPage($event)"
@sort="onSort($event)"
@filter="onFilter($event)"
filterDisplay="row"
:globalFilterFields="['name', 'country.name', 'company', 'representative.name']"
:selectAll="selectAll"
@select-all-change="onSelectAllChange"
@row-select="onRowSelect"
@row-unselect="onRowUnselect"
tableStyle="min-width: 75rem"
>
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name" filterMatchMode="startsWith" sortable>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="country.name" header="Country" filterField="country.name" filterMatchMode="contains" sortable>
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="company" header="Company" filterMatchMode="contains" sortable>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
<Column field="representative.name" header="Representative" filterField="representative.name" sortable>
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search" />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -213,8 +215,8 @@ export default {
this.loading = true;
this.lazyParams = {
first: this.$refs.dt.first,
rows: this.$refs.dt.rows,
first: 0,
rows: 10,
sortField: null,
sortOrder: null,
filters: this.filters
@ -324,8 +326,8 @@ onMounted(() => {
loading.value = true;
lazyParams.value = {
first: dt.value.first,
rows: dt.value.rows,
first: 0,
rows: 10,
sortField: null,
sortOrder: null,
filters: filters.value
@ -425,20 +427,20 @@ const onRowUnselect = () => {
}
};
},
mounted() {
this.loading = true;
this.lazyParams = {
first: this.$refs.dt.first,
rows: this.$refs.dt.rows,
sortField: null,
sortOrder: null,
filters: this.filters
};
this.loadLazyData();
},
methods: {
loadDemoData() {
this.loading = true;
this.lazyParams = {
first: 0,
rows: 10,
sortField: null,
sortOrder: null,
filters: this.filters
};
this.loadLazyData();
},
loadLazyData(event) {
this.loading = true;
this.lazyParams = { ...this.lazyParams, first: event?.first || this.first };

View File

@ -6,12 +6,14 @@
the rows after reorder completes.
</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" reorderableColumns @column-reorder="onColReorder" @row-reorder="onRowReorder" tableStyle="min-width: 50rem">
<Column rowReorder headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" reorderableColumns @column-reorder="onColReorder" @row-reorder="onRowReorder" tableStyle="min-width: 50rem">
<Column rowReorder headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -72,7 +74,7 @@ export default {
}
}
}
<\/script>
<\/script>
`,
composition: `
@ -112,7 +114,7 @@ const onRowReorder = (event) => {
toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
};
<\/script>
<\/script>
`,
data: `
{
@ -139,10 +141,10 @@ const onRowReorder = (event) => {
{ field: 'quantity', header: 'Quantity' }
];
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onColReorder() {
this.$toast.add({ severity: 'success', summary: 'Column Reordered', life: 3000 });
},

View File

@ -9,64 +9,66 @@
<i>&#123;'1004': true&#125;</i>. The <i>dataKey</i> alternative is more performant for large amounts of data.
</p>
</DocSectionText>
<div class="card">
<DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id" @rowExpand="onRowExpand" @rowCollapse="onRowCollapse" tableStyle="min-width: 60rem">
<template #header>
<div class="flex flex-wrap justify-content-end gap-2">
<Button text icon="pi pi-plus" label="Expand All" @click="expandAll" />
<Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column expander style="width: 5rem" />
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-4" width="64" />
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id" @rowExpand="onRowExpand" @rowCollapse="onRowCollapse" tableStyle="min-width: 60rem">
<template #header>
<div class="flex flex-wrap justify-content-end gap-2">
<Button text icon="pi pi-plus" label="Expand All" @click="expandAll" />
<Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
<Column expander style="width: 5rem" />
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-4" width="64" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #expansion="slotProps">
<div class="p-3">
<h5>Orders for {{ slotProps.data.name }}</h5>
<DataTable :value="slotProps.data.orders">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps">
{{ formatCurrency(slotProps.data.amount) }}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<Tag :value="slotProps.data.status.toLowerCase()" :severity="getOrderSeverity(slotProps.data)" />
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #expansion="slotProps">
<div class="p-3">
<h5>Orders for {{ slotProps.data.name }}</h5>
<DataTable :value="slotProps.data.orders">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps">
{{ formatCurrency(slotProps.data.amount) }}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<Tag :value="slotProps.data.status.toLowerCase()" :severity="getOrderSeverity(slotProps.data)" />
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
</div>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -426,10 +428,10 @@ const getOrderSeverity = (order) => {
}
};
},
mounted() {
ProductService.getProductsWithOrdersSmall().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsWithOrdersSmall().then((data) => (this.products = data));
},
onRowExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000 });
},

View File

@ -2,17 +2,19 @@
<DocSectionText v-bind="$attrs">
<p>In addition to a regular table, alternatives with alternative sizes are available.</p>
</DocSectionText>
<div class="card">
<div class="flex justify-content-center mb-4">
<SelectButton v-model="size" :options="sizeOptions" optionLabel="label" dataKey="label" />
<DeferredDemo @load="loadDemoData">
<div class="card">
<div class="flex justify-content-center mb-4">
<SelectButton v-model="size" :options="sizeOptions" optionLabel="label" dataKey="label" />
</div>
<DataTable :value="products" :size="size.value" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DataTable :value="products" :size="size.value" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -126,8 +128,10 @@ const sizeOptions = ref([
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -6,76 +6,78 @@
browser is closed. Other alternative is <i>local</i> referring to <i>localStorage</i> for an extended lifetime.
</p>
</DocSectionText>
<div class="card">
<DataTable
v-model:filters="filters"
v-model:selection="selectedCustomer"
:value="customers"
stateStorage="session"
stateKey="dt-state-demo-session"
paginator
:rows="5"
filterDisplay="menu"
selectionMode="single"
dataKey="id"
:globalFilterFields="['name', 'country.name', 'representative.name', 'status']"
tableStyle="min-width: 50rem"
>
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" sortable style="width: 25%">
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
v-model:filters="filters"
v-model:selection="selectedCustomer"
:value="customers"
stateStorage="session"
stateKey="dt-state-demo-session"
paginator
:rows="5"
filterDisplay="menu"
selectionMode="single"
dataKey="id"
:globalFilterFields="['name', 'country.name', 'representative.name', 'status']"
tableStyle="min-width: 50rem"
>
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Global Search" />
</span>
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width: 25%">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Representative" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="width: 25%">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" sortable filterMatchMode="equals" style="width: 25%">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<template #empty> No customers found. </template>
</DataTable>
</div>
<Column field="name" header="Name" sortable style="width: 25%">
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width: 25%">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Representative" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="width: 25%">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" sortable filterMatchMode="equals" style="width: 25%">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<template #empty> No customers found. </template>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -433,10 +435,10 @@ const getSeverity = (status) => {
created() {
this.initFilters();
},
mounted() {
CustomerService.getCustomersSmall().then((data) => (this.customers = data));
},
methods: {
loadDemoData() {
CustomerService.getCustomersSmall().then((data) => (this.customers = data));
},
initFilters() {
this.filters = {
global: { value: null, matchMode: FilterMatchMode.CONTAINS },

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Alternating rows are displayed when <i>stripedRows</i> property is present.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" stripedRows tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" stripedRows tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,39 +2,41 @@
<DocSectionText v-bind="$attrs">
<p>Custom content at <i>header</i> and <i>footer</i> sections are supported via templating.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div class="flex flex-wrap align-items-center justify-content-between gap-2">
<span class="text-xl text-900 font-bold">Products</span>
<Button icon="pi pi-refresh" rounded raised />
</div>
</template>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-6rem shadow-2 border-round" />
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<template #header>
<div class="flex flex-wrap align-items-center justify-content-between gap-2">
<span class="text-xl text-900 font-bold">Products</span>
<Button icon="pi pi-refresh" rounded raised />
</div>
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #footer> In total there are {{ products ? products.length : 0 }} products. </template>
</DataTable>
</div>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-6rem shadow-2 border-round" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data)" />
</template>
</Column>
<template #footer> In total there are {{ products ? products.length : 0 }} products. </template>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -236,10 +238,10 @@ const getSeverity = (product) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
},

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Setting <i>columnResizeMode</i> as <i>expand</i> changes the table width as well.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" resizableColumns columnResizeMode="expand" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" resizableColumns columnResizeMode="expand" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -96,8 +98,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,14 +5,16 @@
that does not change the overall table width.
</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" resizableColumns columnResizeMode="fit" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" resizableColumns columnResizeMode="fit" showGridlines tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -99,8 +101,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,35 +2,37 @@
<DocSectionText v-bind="$attrs">
<p>Cell editing is enabled by setting <i>editMode</i> as <i>cell</i>, defining input elements with <i>editor</i> templating of a Column and implementing <i>cell-edit-complete</i> to update the state.</p>
</DocSectionText>
<div class="card p-fluid">
<DataTable
:value="products"
editMode="cell"
@cell-edit-complete="onCellEditComplete"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ 'pt-0 pb-0': state['d_editing'] }]
})
}
}"
>
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%">
<template #body="{ data, field }">
{{ field === 'price' ? formatCurrency(data[field]) : data[field] }}
</template>
<template #editor="{ data, field }">
<template v-if="field !== 'price'">
<InputText v-model="data[field]" autofocus />
<DeferredDemo @load="loadDemoData">
<div class="card p-fluid">
<DataTable
:value="products"
editMode="cell"
@cell-edit-complete="onCellEditComplete"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ 'pt-0 pb-0': state['d_editing'] }]
})
}
}"
>
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%">
<template #body="{ data, field }">
{{ field === 'price' ? formatCurrency(data[field]) : data[field] }}
</template>
<template v-else>
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" autofocus />
<template #editor="{ data, field }">
<template v-if="field !== 'price'">
<InputText v-model="data[field]" autofocus />
</template>
<template v-else>
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" autofocus />
</template>
</template>
</template>
</Column>
</DataTable>
</div>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" />
</template>
@ -260,10 +262,10 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onCellEditComplete(event) {
let { data, newValue, field } = event;

View File

@ -2,32 +2,34 @@
<DocSectionText v-bind="$attrs">
<p>Cell Editing with Sorting and Filter</p>
</DocSectionText>
<div class="card p-fluid">
<DataTable
v-model:filters="filters"
:value="products"
editMode="cell"
@cell-edit-complete="onCellEditComplete"
filterDisplay="row"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ 'pt-0 pb-0': state['d_editing'] }]
})
}
}"
>
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%" sortable filter>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" v-tooltip.top.focus="'Hit enter key to filter'" type="text" @keydown.enter="filterCallback()" class="p-column-filter" />
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card p-fluid">
<DataTable
v-model:filters="filters"
:value="products"
editMode="cell"
@cell-edit-complete="onCellEditComplete"
filterDisplay="row"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ 'pt-0 pb-0': state['d_editing'] }]
})
}
}"
>
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%" sortable filter>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" v-tooltip.top.focus="'Hit enter key to filter'" type="text" @keydown.enter="filterCallback()" class="p-column-filter" />
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" />
</template>
@ -271,10 +273,10 @@ const isPositiveInteger = (val) => {
{ field: 'price', header: 'Price' }
];
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onCellEditComplete(event) {
let { data, newValue, field } = event;

View File

@ -5,55 +5,57 @@
<i>editor</i> slot of a Column and implementing <i>row-edit-save</i> are necessary to update the state. The column to control the editing state should have <i>editor</i> templating applied.
</p>
</DocSectionText>
<div class="card p-fluid">
<DataTable
v-model:editingRows="editingRows"
:value="products"
editMode="row"
dataKey="id"
@row-edit-save="onRowEditSave"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing'] && 'padding-top: 0.6rem; padding-bottom: 0.6rem'
})
}
}"
>
<Column field="code" header="Code" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="name" header="Name" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width: 20%">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<template #option="slotProps">
<Tag :value="slotProps.option.value" :severity="getStatusLabel(slotProps.option.value)" />
</template>
</Dropdown>
</template>
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column field="price" header="Price" style="width: 20%">
<template #body="{ data, field }">
{{ formatCurrency(data[field]) }}
</template>
<template #editor="{ data, field }">
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card p-fluid">
<DataTable
v-model:editingRows="editingRows"
:value="products"
editMode="row"
dataKey="id"
@row-edit-save="onRowEditSave"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing'] && 'padding-top: 0.6rem; padding-bottom: 0.6rem'
})
}
}"
>
<Column field="code" header="Code" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="name" header="Name" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width: 20%">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<template #option="slotProps">
<Tag :value="slotProps.option.value" :severity="getStatusLabel(slotProps.option.value)" />
</template>
</Dropdown>
</template>
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column field="price" header="Price" style="width: 20%">
<template #body="{ data, field }">
{{ formatCurrency(data[field]) }}
</template>
<template #editor="{ data, field }">
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" />
</template>
@ -77,7 +79,7 @@ export default {
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
})
}
}"
@ -123,7 +125,7 @@ export default {
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
})
}
}"
@ -217,7 +219,7 @@ export default {
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
style: state['d_editing']&&'padding-top: 0.6rem; padding-bottom: 0.6rem'
})
}
}"
@ -317,10 +319,10 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowEditSave(event) {
let { newData, index } = event;

View File

@ -2,116 +2,118 @@
<DocSectionText v-bind="$attrs">
<p>When <i>filterDisplay</i> is set as <i>menu</i>, filtering is done via popups with support for multiple constraints and advanced templating.</p>
</DocSectionText>
<div class="card">
<DataTable v-model:filters="filters" :value="customers" paginator showGridlines :rows="10" dataKey="id" filterDisplay="menu" :loading="loading" :globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']">
<template #header>
<div class="flex justify-content-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:filters="filters" :value="customers" paginator showGridlines :rows="10" dataKey="id" filterDisplay="menu" :loading="loading" :globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']">
<template #header>
<div class="flex justify-content-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
<template #filterclear="{ filterCallback }">
<Button type="button" icon="pi pi-times" @click="filterCallback()" severity="secondary"></Button>
</template>
<template #filterapply="{ filterCallback }">
<Button type="button" icon="pi pi-check" @click="filterCallback()" severity="success"></Button>
</template>
<template #filterfooter>
<div class="px-3 pt-0 pb-3 text-center">Customized Buttons</div>
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column header="Date" filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />
</template>
</Column>
<Column header="Balance" filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="activity" header="Activity" :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-3"></Slider>
<div class="flex align-items-center justify-content-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" bodyClass="text-center" style="min-width: 8rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500 ': data.verified, 'pi-times-circle text-red-500': !data.verified }"></i>
</template>
<template #filter="{ filterModel }">
<label for="verified-filter" class="font-bold"> Verified </label>
<TriStateCheckbox v-model="filterModel.value" inputId="verified-filter" />
</template>
</Column>
</DataTable>
</div>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
<template #filterclear="{ filterCallback }">
<Button type="button" icon="pi pi-times" @click="filterCallback()" severity="secondary"></Button>
</template>
<template #filterapply="{ filterCallback }">
<Button type="button" icon="pi pi-check" @click="filterCallback()" severity="success"></Button>
</template>
<template #filterfooter>
<div class="px-3 pt-0 pb-3 text-center">Customized Buttons</div>
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column header="Date" filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />
</template>
</Column>
<Column header="Balance" filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="activity" header="Activity" :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-3"></Slider>
<div class="flex align-items-center justify-content-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" bodyClass="text-center" style="min-width: 8rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500 ': data.verified, 'pi-times-circle text-red-500': !data.verified }"></i>
</template>
<template #filter="{ filterModel }">
<label for="verified-filter" class="font-bold"> Verified </label>
<TriStateCheckbox v-model="filterModel.value" inputId="verified-filter" />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -682,13 +684,13 @@ const getSeverity = (status) => {
created() {
this.initFilters();
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = this.getCustomers(data);
this.loading = false;
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = this.getCustomers(data);
this.loading = false;
});
},
formatDate(value) {
return value.toLocaleDateString('en-US', {
day: '2-digit',

View File

@ -6,77 +6,79 @@
</p>
<p>The optional global filtering searches the data against a single value that is bound to the <i>global</i> key of the <i>filters</i> object. The fields to search against is defined with the <i>globalFilterFields</i>.</p>
</DocSectionText>
<div class="card">
<DataTable v-model:filters="filters" :value="customers" paginator :rows="10" dataKey="id" filterDisplay="row" :loading="loading" :globalFilterFields="['name', 'country.name', 'representative.name', 'status']">
<template #header>
<div class="flex justify-content-end">
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:filters="filters" :value="customers" paginator :rows="10" dataKey="id" filterDisplay="row" :loading="loading" :globalFilterFields="['name', 'country.name', 'representative.name', 'status']">
<template #header>
<div class="flex justify-content-end">
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMenu="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<MultiSelect v-model="filterModel.value" @change="filterCallback()" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter" style="min-width: 14rem" :maxSelectedLabels="1">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :showFilterMenu="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel, filterCallback }">
<Dropdown v-model="filterModel.value" @change="filterCallback()" :options="statuses" placeholder="Select One" class="p-column-filter" style="min-width: 12rem" :showClear="true">
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" style="min-width: 6rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500': data.verified, 'pi-times-circle text-red-400': !data.verified }"></i>
</template>
<template #filter="{ filterModel, filterCallback }">
<TriStateCheckbox v-model="filterModel.value" @change="filterCallback()" />
</template>
</Column>
</DataTable>
</div>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<InputText v-model="filterModel.value" type="text" @input="filterCallback()" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMenu="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel, filterCallback }">
<MultiSelect v-model="filterModel.value" @change="filterCallback()" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter" style="min-width: 14rem" :maxSelectedLabels="1">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :showFilterMenu="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel, filterCallback }">
<Dropdown v-model="filterModel.value" @change="filterCallback()" :options="statuses" placeholder="Select One" class="p-column-filter" style="min-width: 12rem" :showClear="true">
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" style="min-width: 6rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500': data.verified, 'pi-times-circle text-red-400': !data.verified }"></i>
</template>
<template #filter="{ filterModel, filterCallback }">
<TriStateCheckbox v-model="filterModel.value" @change="filterCallback()" />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -510,13 +512,13 @@ const getSeverity = (status) => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = this.getCustomers(data);
this.loading = false;
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = this.getCustomers(data);
this.loading = false;
});
},
getCustomers(data) {
return [...(data || [])].map((d) => {
d.date = new Date(d.date);

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Pagination is enabled by adding <i>paginator</i> property and defining <i>rows</i> per page.</p>
</DocSectionText>
<div class="card">
<DataTable :value="customers" paginator :rows="5" :rowsPerPageOptions="[5, 10, 20, 50]" tableStyle="min-width: 50rem">
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="customers" paginator :rows="5" :rowsPerPageOptions="[5, 10, 20, 50]" tableStyle="min-width: 50rem">
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -104,8 +106,10 @@ const customers = ref();
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
}
}
};
</script>

View File

@ -5,28 +5,30 @@
<PrimeVueNuxtLink to="/paginator">Paginator</PrimeVueNuxtLink> component for more information about the advanced customization options.
</p>
</DocSectionText>
<div class="card">
<DataTable
:value="customers"
paginator
:rows="5"
:rowsPerPageOptions="[5, 10, 20, 50]"
paginatorTemplate="RowsPerPageDropdown FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink"
currentPageReportTemplate="{first} to {last} of {totalRecords}"
tableStyle="min-width: 50rem"
>
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" text />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-download" text />
</template>
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
:value="customers"
paginator
:rows="5"
:rowsPerPageOptions="[5, 10, 20, 50]"
paginatorTemplate="RowsPerPageDropdown FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink"
currentPageReportTemplate="{first} to {last} of {totalRecords}"
tableStyle="min-width: 50rem"
>
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" text />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-download" text />
</template>
<Column field="name" header="Name" style="width: 25%"></Column>
<Column field="country.name" header="Country" style="width: 25%"></Column>
<Column field="company" header="Company" style="width: 25%"></Column>
<Column field="representative.name" header="Representative" style="width: 25%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -145,8 +147,10 @@ const customers = ref();
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
}
}
};
</script>

View File

@ -1,51 +1,53 @@
<template>
<DocSectionText v-bind="$attrs"></DocSectionText>
<div class="card">
<DataTable
:value="products"
sortMode="multiple"
:pt="{
table: { style: { minWidth: '50rem' } }
}"
>
<Column
field="code"
header="Code"
sortable
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
:value="products"
sortMode="multiple"
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
table: { style: { minWidth: '50rem' } }
}"
/>
<Column
field="name"
header="Name"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
<Column
field="category"
header="Category"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
<Column
field="quantity"
header="Quantity"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
</DataTable>
</div>
>
<Column
field="code"
header="Code"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
<Column
field="name"
header="Name"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
<Column
field="category"
header="Category"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
<Column
field="quantity"
header="Quantity"
sortable
:pt="{
sortBadge: { class: 'bg-primary' },
headerCell: { style: { width: '25%' } }
}"
/>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -248,8 +250,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,46 +5,48 @@
<i>rowgroup-collapse</i> events.
</p>
</DocSectionText>
<div class="card">
<DataTable
v-model:expandedRowGroups="expandedRowGroups"
:value="customers"
expandableRowGroups
rowGroupMode="subheader"
groupRowsBy="representative.name"
sortMode="single"
sortField="representative.name"
:sortOrder="1"
@rowgroup-expand="onRowGroupExpand"
@rowgroup-collapse="onRowGroupCollapse"
tableStyle="min-width: 50rem"
>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" class="ml-2" />
<span class="vertical-align-middle ml-2 font-bold line-height-3">{{ slotProps.data.representative.name }}</span>
</template>
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="width: 20%"></Column>
<Column field="country" header="Country" style="width: 20%">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
v-model:expandedRowGroups="expandedRowGroups"
:value="customers"
expandableRowGroups
rowGroupMode="subheader"
groupRowsBy="representative.name"
sortMode="single"
sortField="representative.name"
:sortOrder="1"
@rowgroup-expand="onRowGroupExpand"
@rowgroup-collapse="onRowGroupCollapse"
tableStyle="min-width: 50rem"
>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" class="ml-2" />
<span class="vertical-align-middle ml-2 font-bold line-height-3">{{ slotProps.data.representative.name }}</span>
</template>
</Column>
<Column field="company" header="Company" style="width: 20%"></Column>
<Column field="status" header="Status" style="width: 20%">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="width: 20%"></Column>
<Column field="country" header="Country" style="width: 20%">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="width: 20%"></Column>
<Column field="status" header="Status" style="width: 20%">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="width: 20%"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</Column>
<Column field="date" header="Date" style="width: 20%"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
</div>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -240,7 +242,7 @@ const calculateCustomerTotal = (name) => {
}
}
}
return total;
};
const getSeverity = (status) => {
@ -286,10 +288,10 @@ const getSeverity = (status) => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
onRowGroupExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000 });
},

View File

@ -2,39 +2,41 @@
<DocSectionText v-bind="$attrs">
<p>When <i>rowGroupMode</i> is configured to be <i>rowspan</i>, the grouping column spans multiple rows.</p>
</DocSectionText>
<div class="card">
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" tableStyle="min-width: 50rem">
<Column header="#" headerStyle="width:3rem">
<template #body="slotProps">
{{ slotProps.index + 1 }}
</template>
</Column>
<Column field="representative.name" header="Representative" style="min-width: 200px">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
</Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 150px">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 100px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="min-width: 100px"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" tableStyle="min-width: 50rem">
<Column header="#" headerStyle="width:3rem">
<template #body="slotProps">
{{ slotProps.index + 1 }}
</template>
</Column>
<Column field="representative.name" header="Representative" style="min-width: 200px">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
</Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 150px">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 100px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="min-width: 100px"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -242,10 +244,10 @@ const getSeverity = (status) => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
onRowGroupExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000 });
},

View File

@ -5,36 +5,38 @@
with <i>groupfooter</i> slots.
</p>
</DocSectionText>
<div class="card">
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<template #groupheader="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<template #groupheader="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
</div>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -214,7 +216,7 @@ const calculateCustomerTotal = (name) => {
}
}
}
return total;
};
const getSeverity = (status) => {
@ -260,10 +262,10 @@ const getSeverity = (status) => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
calculateCustomerTotal(name) {
let total = 0;

View File

@ -3,15 +3,17 @@
<p>Specifying <i>selectionMode</i> as <i>multiple</i> on a Column, displays a checkbox inside that column for selection.</p>
<p>The header checkbox toggles the selection state of the whole dataset by default, when paginator is enabled you may add <i>selectAll</i> property and <i>select-all-change</i> event to only control the selection of visible rows.</p>
</DocSectionText>
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -109,8 +111,10 @@ const metaKey = ref(true);
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,18 +5,20 @@
<i>metaKeySelection</i> is present, behavior is changed in a way that selecting a new row requires meta key to be present. Note that in touch enabled devices, DataTable always ignores metaKey.
</p>
</DocSectionText>
<div class="card">
<div class="flex justify-content-center align-items-center mb-4 gap-2">
<InputSwitch v-model="metaKey" inputId="input-metakey" />
<label for="input-metakey">MetaKey</label>
<DeferredDemo @load="loadDemoData">
<div class="card">
<div class="flex justify-content-center align-items-center mb-4 gap-2">
<InputSwitch v-model="metaKey" inputId="input-metakey" />
<label for="input-metakey">MetaKey</label>
</div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="multiple" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="multiple" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -121,8 +123,10 @@ const metaKey = ref(true);
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,15 +5,17 @@
trigger selection using the radio buttons.
</p>
</DocSectionText>
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="single" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column selectionMode="single" headerStyle="width: 3rem"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -111,8 +113,10 @@ const metaKey = ref(true);
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>DataTable provides <i>row-select</i> and <i>row-unselect</i> events to listen selection events.</p>
</DocSectionText>
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" dataKey="id" :metaKeySelection="false" @rowSelect="onRowSelect" @rowUnselect="onRowUnselect" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" dataKey="id" :metaKeySelection="false" @rowSelect="onRowSelect" @rowUnselect="onRowUnselect" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -124,10 +126,10 @@ const onRowUnselect = (event) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowSelect(event) {
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000 });
},

View File

@ -9,18 +9,20 @@
setting it to false.
</p>
</DocSectionText>
<div class="card">
<div class="flex justify-content-center align-items-center mb-4 gap-2">
<InputSwitch v-model="metaKey" inputId="input-metakey" />
<label for="input-metakey">MetaKey</label>
<DeferredDemo @load="loadDemoData">
<div class="card">
<div class="flex justify-content-center align-items-center mb-4 gap-2">
<InputSwitch v-model="metaKey" inputId="input-metakey" />
<label for="input-metakey">MetaKey</label>
</div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -125,8 +127,10 @@ const metaKey = ref(true);
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,103 +2,114 @@
<DocSectionText v-bind="$attrs">
<p>DataTable with selection, pagination, filtering, sorting and templating.</p>
</DocSectionText>
<div class="card">
<DataTable v-model:filters="filters" v-model:selection="selectedCustomers" :value="customers" paginator :rows="10" dataKey="id" filterDisplay="menu" :globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']">
<template #header>
<div class="flex justify-content-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #empty> No customers found. </template>
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 14rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
v-model:filters="filters"
v-model:selection="selectedCustomers"
:value="customers"
paginator
:rows="10"
dataKey="id"
filterDisplay="menu"
:globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']"
>
<template #header>
<div class="flex justify-content-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="date" header="Date" sortable filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />
</template>
</Column>
<Column field="balance" header="Balance" sortable filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" sortable field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="activity" header="Activity" sortable :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-3"></Slider>
<div class="flex align-items-center justify-content-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column headerStyle="width: 5rem; text-align: center" bodyStyle="text-align: center; overflow: visible">
<template #body>
<Button type="button" icon="pi pi-cog" rounded />
</template>
</Column>
</DataTable>
</div>
<template #empty> No customers found. </template>
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 14rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" sortable sortField="country.name" filterField="country.name" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" sortable sortField="representative.name" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex align-items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="flex align-items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="date" header="Date" sortable filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" mask="99/99/9999" />
</template>
</Column>
<Column field="balance" header="Balance" sortable filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" sortable field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Select One" class="p-column-filter" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Dropdown>
</template>
</Column>
<Column field="activity" header="Activity" sortable :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-3"></Slider>
<div class="flex align-items-center justify-content-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column headerStyle="width: 5rem; text-align: center" bodyStyle="text-align: center; overflow: visible">
<template #body>
<Button type="button" icon="pi pi-cog" rounded />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -628,12 +639,12 @@ const getSeverity = (status) => {
created() {
this.initFilters();
},
mounted() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = this.getCustomers(data);
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = this.getCustomers(data);
});
},
formatDate(value) {
return value.toLocaleDateString('en-US', {
day: '2-digit',

View File

@ -2,73 +2,75 @@
<DocSectionText v-bind="$attrs">
<p>CRUD implementation example with a Dialog.</p>
</DocSectionText>
<div class="card">
<Toolbar class="mb-4">
<template #start>
<Button label="New" icon="pi pi-plus" severity="success" class="mr-2" @click="openNew" />
<Button label="Delete" icon="pi pi-trash" severity="danger" @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
</template>
<DeferredDemo @load="loadDemoData">
<div class="card">
<Toolbar class="mb-4">
<template #start>
<Button label="New" icon="pi pi-plus" severity="success" class="mr-2" @click="openNew" />
<Button label="Delete" icon="pi pi-trash" severity="danger" @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
</template>
<template #end>
<FileUpload mode="basic" accept="image/*" :maxFileSize="1000000" label="Import" chooseLabel="Import" class="mr-2 inline-block" />
<Button label="Export" icon="pi pi-upload" severity="help" @click="exportCSV($event)" />
</template>
</Toolbar>
<template #end>
<FileUpload mode="basic" accept="image/*" :maxFileSize="1000000" label="Import" chooseLabel="Import" class="mr-2 inline-block" />
<Button label="Export" icon="pi pi-upload" severity="help" @click="exportCSV($event)" />
</template>
</Toolbar>
<DataTable
ref="dt"
v-model:selection="selectedProducts"
:value="products"
dataKey="id"
:paginator="true"
:rows="10"
:filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rowsPerPageOptions="[5, 10, 25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
>
<template #header>
<div class="flex flex-wrap gap-2 align-items-center justify-content-between">
<h4 class="m-0">Manage Products</h4>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Search..." />
</span>
</div>
</template>
<DataTable
ref="dt"
v-model:selection="selectedProducts"
:value="products"
dataKey="id"
:paginator="true"
:rows="10"
:filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rowsPerPageOptions="[5, 10, 25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
>
<template #header>
<div class="flex flex-wrap gap-2 align-items-center justify-content-between">
<h4 class="m-0">Manage Products</h4>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Search..." />
</span>
</div>
</template>
<Column selectionMode="multiple" style="width: 3rem" :exportable="false"></Column>
<Column field="code" header="Code" sortable style="min-width: 12rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 16rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-2 border-round" style="width: 64px" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="min-width: 10rem"></Column>
<Column field="rating" header="Reviews" sortable style="min-width: 12rem">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable style="min-width: 12rem">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column :exportable="false" style="min-width: 12rem">
<template #body="slotProps">
<Button icon="pi pi-pencil" outlined rounded class="mr-2" @click="editProduct(slotProps.data)" />
<Button icon="pi pi-trash" outlined rounded severity="danger" @click="confirmDeleteProduct(slotProps.data)" />
</template>
</Column>
</DataTable>
</div>
<Column selectionMode="multiple" style="width: 3rem" :exportable="false"></Column>
<Column field="code" header="Code" sortable style="min-width: 12rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 16rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-2 border-round" style="width: 64px" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="min-width: 10rem"></Column>
<Column field="rating" header="Reviews" sortable style="min-width: 12rem">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable style="min-width: 12rem">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column :exportable="false" style="min-width: 12rem">
<template #body="slotProps">
<Button icon="pi pi-pencil" outlined rounded class="mr-2" @click="editProduct(slotProps.data)" />
<Button icon="pi pi-trash" outlined rounded severity="danger" @click="confirmDeleteProduct(slotProps.data)" />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<Dialog v-model:visible="productDialog" :style="{ width: '450px' }" header="Product Details" :modal="true" class="p-fluid">
<img v-if="product.image" :src="`https://primefaces.org/cdn/primevue/images/product/${product.image}`" :alt="product.image" class="block m-auto pb-3" />
@ -197,7 +199,7 @@ export default {
<Button label="Export" icon="pi pi-upload" severity="help" @click="exportCSV($event)" />
</template>
</Toolbar>
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
:paginator="true" :rows="10" :filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown" :rowsPerPageOptions="[5,10,25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products">
@ -258,7 +260,7 @@ export default {
</template>
</Toolbar>
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
:paginator="true" :rows="10" :filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown" :rowsPerPageOptions="[5,10,25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products">
@ -547,7 +549,7 @@ export default {
</template>
</Toolbar>
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
<DataTable ref="dt" :value="products" v-model:selection="selectedProducts" dataKey="id"
:paginator="true" :rows="10" :filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown" :rowsPerPageOptions="[5,10,25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products">
@ -830,14 +832,13 @@ const getStatusLabel = (status) => {
}
};
},
created() {
this.initFilters();
},
mounted() {
ProductService.getProducts().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProducts().then((data) => (this.products = data));
},
formatCurrency(value) {
if (value) return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });

View File

@ -8,7 +8,7 @@
<div class="card flex justify-content-center">
<Button label="Show" icon="pi pi-external-link" @click="dialogVisible = true" />
<Dialog v-model:visible="dialogVisible" header="Flex Scroll" :style="{ width: '75vw' }" maximizable modal :contentStyle="{ height: '300px' }">
<Dialog v-model:visible="dialogVisible" header="Flex Scroll" :style="{ width: '75vw' }" maximizable modal :contentStyle="{ height: '300px' }" @show="onShow">
<DataTable :value="customers" scrollable scrollHeight="flex" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
@ -140,10 +140,12 @@ onMounted(() => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
methods: {
onShow() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
}
}
};
</script>

View File

@ -2,26 +2,28 @@
<DocSectionText v-bind="$attrs">
<p>A column can be fixed during horizontal scrolling by enabling the <i>frozen</i> property. The location is defined with the <i>alignFrozen</i> that can be <i>left</i> or <i>right</i>.</p>
</DocSectionText>
<div class="card">
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Balance" offLabel="Balance" />
<DeferredDemo @load="loadDemoData">
<div class="card">
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Balance" offLabel="Balance" />
<DataTable :value="customers" scrollable scrollHeight="400px" class="mt-4">
<Column field="name" header="Name" style="min-width: 200px" frozen class="font-bold"></Column>
<Column field="id" header="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template>
</Column>
</DataTable>
</div>
<DataTable :value="customers" scrollable scrollHeight="400px" class="mt-4">
<Column field="name" header="Name" style="min-width: 200px" frozen class="font-bold"></Column>
<Column field="id" header="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -165,12 +167,12 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = data;
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = data;
});
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}

View File

@ -2,30 +2,32 @@
<DocSectionText v-bind="$attrs">
<p>Rows can be fixed during scrolling by enabling the <i>frozenValue</i> property.</p>
</DocSectionText>
<div class="card">
<DataTable
:value="customers"
:frozenValue="lockedCustomers"
scrollable
scrollHeight="400px"
:pt="{
table: { style: 'min-width: 50rem' },
bodyrow: ({ props }) => ({
class: [{ 'font-bold': props.frozenRow }]
})
}"
>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{ data, frozenRow, index }">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2" text size="small" @click="toggleLock(data, frozenRow, index)" />
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
:value="customers"
:frozenValue="lockedCustomers"
scrollable
scrollHeight="400px"
:pt="{
table: { style: 'min-width: 50rem' },
bodyrow: ({ props }) => ({
class: [{ 'font-bold': props.frozenRow }]
})
}"
>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{ data, frozenRow, index }">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2" text size="small" @click="toggleLock(data, frozenRow, index)" />
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -255,12 +257,12 @@ onMounted(() => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
},
toggleLock(data, frozen, index) {
if (frozen) {
this.lockedCustomers = this.lockedCustomers.filter((c, i) => i !== index);

View File

@ -2,23 +2,25 @@
<DocSectionText v-bind="$attrs">
<p>Horizontal scrollbar is displayed when table width exceeds the parent width.</p>
</DocSectionText>
<div class="card">
<DataTable :value="customers" scrollable scrollHeight="400px">
<Column field="id" header="Id" footer="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" footer="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" footer="Date" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="min-width: 200px">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" footer="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="min-width: 200px"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="customers" scrollable scrollHeight="400px">
<Column field="id" header="Id" footer="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" footer="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" footer="Date" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="min-width: 200px">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" footer="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="min-width: 200px"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -152,12 +154,12 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
},
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Adding <i>scrollable</i> property along with a <i>scrollHeight</i> for the data viewport enables vertical scrolling with fixed headers.</p>
</DocSectionText>
<div class="card">
<DataTable :value="customers" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="customers" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" />
</template>
@ -107,10 +109,12 @@ onMounted(() => {
}
};
},
mounted() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => {
this.customers = data;
});
}
}
};
</script>

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Multiple columns can be sorted by defining <i>sortMode</i> as <i>multiple</i>. This mode requires metaKey (e.g. <i></i>) to be pressed when clicking a header.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" sortMode="multiple" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" sortMode="multiple" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -5,19 +5,21 @@
<i>DataTableSortMeta</i> objects.
</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" sortField="price" :sortOrder="-1" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 20%"></Column>
<Column field="name" header="Name" sortable style="width: 20%"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="width: 20%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 20%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" sortField="price" :sortOrder="-1" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 20%"></Column>
<Column field="name" header="Name" sortable style="width: 20%"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="width: 20%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 20%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -129,10 +131,10 @@ const formatCurrency = (value) => {
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>When <i>removableSort</i> is present, the third click removes the sorting from the column.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" removableSort tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" removableSort tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs">
<p>Sorting on a column is enabled by adding the <i>sortable</i> property.</p>
</DocSectionText>
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" />
</template>
@ -98,8 +100,10 @@ const products = ref();
}
};
},
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
}
};
</script>

View File

@ -3,51 +3,53 @@
<p>When lazy loading is enabled via the <i>virtualScrollerOptions</i>, data is fetched on demand during scrolling instead of preload.</p>
<p>In sample below, an in-memory list and timeout is used to mimic fetching from a remote datasource. The <i>virtualCars</i> is an empty array that is populated on scroll.</p>
</DocSectionText>
<div class="card">
<DataTable
:value="virtualCars"
scrollable
scrollHeight="400px"
:virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }"
tableStyle="min-width: 50rem"
>
<Column field="id" header="Id" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable
:value="virtualCars"
scrollable
scrollHeight="400px"
:virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }"
tableStyle="min-width: 50rem"
>
<Column field="id" header="Id" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="width: 20%">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CarService']" />
</template>
@ -280,10 +282,10 @@ const loadCarsLazy = (event) => {
}
};
},
mounted() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
},
methods: {
loadDemoData() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
},
loadCarsLazy(event) {
!this.lazyLoading && (this.lazyLoading = true);

View File

@ -6,15 +6,17 @@
</p>
<p>In this example, <strong>100000</strong> preloaded records are rendered by the Table.</p>
</DocSectionText>
<div class="card">
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }" tableStyle="min-width: 50rem">
<Column field="id" header="Id" style="width: 20%"></Column>
<Column field="vin" header="Vin" style="width: 20%"></Column>
<Column field="year" header="Year" style="width: 20%"></Column>
<Column field="brand" header="Brand" style="width: 20%"></Column>
<Column field="color" header="Color" style="width: 20%"></Column>
</DataTable>
</div>
<DeferredDemo @load="loadDemoData">
<div class="card">
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }" tableStyle="min-width: 50rem">
<Column field="id" header="Id" style="width: 20%"></Column>
<Column field="vin" header="Vin" style="width: 20%"></Column>
<Column field="year" header="Year" style="width: 20%"></Column>
<Column field="brand" header="Brand" style="width: 20%"></Column>
<Column field="color" header="Color" style="width: 20%"></Column>
</DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CarService']" />
</template>
@ -98,8 +100,10 @@ onMounted(() => {
}
};
},
mounted() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
methods: {
loadDemoData() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
}
}
};
</script>

View File

@ -1,5 +1,7 @@
import DeferredDemo from '@/components/demo/DeferredDemo.vue';
import CodeHighlight from '@/directives/CodeHighlight';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('code', CodeHighlight);
nuxtApp.vueApp.component('DeferredDemo', DeferredDemo); // @todo
});