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

View File

@ -5,50 +5,52 @@
to span are defined with the <i>colspan</i> and <i>rowspan</i> properties of a Column. to span are defined with the <i>colspan</i> and <i>rowspan</i> properties of a Column.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="sales" tableStyle="min-width: 50rem"> <div class="card">
<ColumnGroup type="header"> <DataTable :value="sales" tableStyle="min-width: 50rem">
<Row> <ColumnGroup type="header">
<Column header="Product" :rowspan="3" /> <Row>
<Column header="Sale Rate" :colspan="4" /> <Column header="Product" :rowspan="3" />
</Row> <Column header="Sale Rate" :colspan="4" />
<Row> </Row>
<Column header="Sales" :colspan="2" /> <Row>
<Column header="Profits" :colspan="2" /> <Column header="Sales" :colspan="2" />
</Row> <Column header="Profits" :colspan="2" />
<Row> </Row>
<Column header="Last Year" sortable field="lastYearSale" /> <Row>
<Column header="This Year" sortable field="thisYearSale" /> <Column header="Last Year" sortable field="lastYearSale" />
<Column header="Last Year" sortable field="lastYearProfit" /> <Column header="This Year" sortable field="thisYearSale" />
<Column header="This Year" sortable field="thisYearProfit" /> <Column header="Last Year" sortable field="lastYearProfit" />
</Row> <Column header="This Year" sortable field="thisYearProfit" />
</ColumnGroup> </Row>
<Column field="product" /> </ColumnGroup>
<Column field="lastYearSale"> <Column field="product" />
<template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template> <Column field="lastYearSale">
</Column> <template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template>
<Column field="thisYearSale"> </Column>
<template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template> <Column field="thisYearSale">
</Column> <template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template>
<Column field="lastYearProfit"> </Column>
<template #body="slotProps"> <Column field="lastYearProfit">
{{ formatCurrency(slotProps.data.lastYearProfit) }} <template #body="slotProps">
</template> {{ formatCurrency(slotProps.data.lastYearProfit) }}
</Column> </template>
<Column field="thisYearProfit"> </Column>
<template #body="slotProps"> <Column field="thisYearProfit">
{{ formatCurrency(slotProps.data.thisYearProfit) }} <template #body="slotProps">
</template> {{ formatCurrency(slotProps.data.thisYearProfit) }}
</Column> </template>
<ColumnGroup type="footer"> </Column>
<Row> <ColumnGroup type="footer">
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right" /> <Row>
<Column :footer="lastYearTotal" /> <Column footer="Totals:" :colspan="3" footerStyle="text-align:right" />
<Column :footer="thisYearTotal" /> <Column :footer="lastYearTotal" />
</Row> <Column :footer="thisYearTotal" />
</ColumnGroup> </Row>
</DataTable> </ColumnGroup>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" /> <DocSectionCode :code="code" />
</template> </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: { 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) { formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
} }

View File

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

View File

@ -2,20 +2,22 @@
<DocSectionText v-bind="$attrs"> <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> <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> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="products" :rowClass="rowClass" :rowStyle="rowStyle" tableStyle="min-width: 50rem"> <div class="card">
<Column field="code" header="Code"></Column> <DataTable :value="products" :rowClass="rowClass" :rowStyle="rowStyle" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column> <Column field="code" header="Code"></Column>
<Column field="category" header="Category"></Column> <Column field="name" header="Name"></Column>
<Column field="quantity" header="Quantity"> <Column field="category" header="Category"></Column>
<template #body="slotProps"> <Column field="quantity" header="Quantity">
<div :class="stockClass(slotProps.data)"> <template #body="slotProps">
{{ slotProps.data.quantity }} <div :class="stockClass(slotProps.data)">
</div> {{ slotProps.data.quantity }}
</template> </div>
</Column> </template>
</DataTable> </Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -119,7 +121,7 @@ import { ProductService } from '@/service/ProductService';
onMounted(() => { onMounted(() => {
ProductService.getProductsSmall().then((data) => (this.products = data)); ProductService.getProductsSmall().then((data) => (this.products = data));
}); });
const products = ref(); const products = ref();
const rowClass = (data) => { const rowClass = (data) => {
@ -160,10 +162,10 @@ const stockClass = (data) => {
} }
}; };
}, },
mounted() {
ProductService.getProductsSmall().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsSmall().then((data) => (this.products = data));
},
rowClass(data) { rowClass(data) {
return [{ 'bg-primary': data.category === 'Fitness' }]; 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. 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> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" /> <div class="card">
<DataTable v-model:contextMenuSelection="selectedProduct" :value="products" contextMenu @row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem"> <ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" />
<Column field="code" header="Code"></Column> <DataTable v-model:contextMenuSelection="selectedProduct" :value="products" contextMenu @row-contextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column> <Column field="code" header="Code"></Column>
<Column field="category" header="Category"></Column> <Column field="name" header="Name"></Column>
<Column field="price" header="Price"> <Column field="category" header="Category"></Column>
<template #body="slotProps"> <Column field="price" header="Price">
{{ formatCurrency(slotProps.data.price) }} <template #body="slotProps">
</template> {{ formatCurrency(slotProps.data.price) }}
</Column> </template>
</DataTable> </Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -51,7 +53,7 @@ export default {
<template> <template>
<div class="card"> <div class="card">
<ContextMenu ref="cm" :model="menuModel" @hide="selectedProduct = null" /> <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"> @rowContextmenu="onRowContextMenu" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column> <Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column> <Column field="name" header="Name"></Column>
@ -174,10 +176,10 @@ const formatCurrency = (value) => {
} }
}; };
}, },
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowContextMenu(event) { onRowContextMenu(event) {
this.$refs.cm.show(event.originalEvent); this.$refs.cm.show(event.originalEvent);
}, },

View File

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

View File

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

View File

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

View File

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

View File

@ -6,12 +6,14 @@
the rows after reorder completes. the rows after reorder completes.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="products" reorderableColumns @column-reorder="onColReorder" @row-reorder="onRowReorder" tableStyle="min-width: 50rem"> <div class="card">
<Column rowReorder headerStyle="width: 3rem" :reorderableColumn="false" /> <DataTable :value="products" reorderableColumns @column-reorder="onColReorder" @row-reorder="onRowReorder" tableStyle="min-width: 50rem">
<Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column> <Column rowReorder headerStyle="width: 3rem" :reorderableColumn="false" />
</DataTable> <Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -72,7 +74,7 @@ export default {
} }
} }
} }
<\/script> <\/script>
`, `,
composition: ` composition: `
@ -112,7 +114,7 @@ const onRowReorder = (event) => {
toast.add({severity:'success', summary: 'Rows Reordered', life: 3000}); toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
}; };
<\/script> <\/script>
`, `,
data: ` data: `
{ {
@ -139,10 +141,10 @@ const onRowReorder = (event) => {
{ field: 'quantity', header: 'Quantity' } { field: 'quantity', header: 'Quantity' }
]; ];
}, },
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onColReorder() { onColReorder() {
this.$toast.add({ severity: 'success', summary: 'Column Reordered', life: 3000 }); 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. <i>&#123;'1004': true&#125;</i>. The <i>dataKey</i> alternative is more performant for large amounts of data.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id" @rowExpand="onRowExpand" @rowCollapse="onRowCollapse" tableStyle="min-width: 60rem"> <div class="card">
<template #header> <DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id" @rowExpand="onRowExpand" @rowCollapse="onRowCollapse" tableStyle="min-width: 60rem">
<div class="flex flex-wrap justify-content-end gap-2"> <template #header>
<Button text icon="pi pi-plus" label="Expand All" @click="expandAll" /> <div class="flex flex-wrap justify-content-end gap-2">
<Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" /> <Button text icon="pi pi-plus" label="Expand All" @click="expandAll" />
</div> <Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</template> </div>
<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> </template>
</Column> <Column expander style="width: 5rem" />
<Column field="price" header="Price"> <Column field="name" header="Name"></Column>
<template #body="slotProps"> <Column header="Image">
{{ formatCurrency(slotProps.data.price) }} <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> </template>
</Column> </DataTable>
<Column field="category" header="Category"></Column> </div>
<Column field="rating" header="Reviews"> </DeferredDemo>
<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>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -426,10 +428,10 @@ const getOrderSeverity = (order) => {
} }
}; };
}, },
mounted() {
ProductService.getProductsWithOrdersSmall().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsWithOrdersSmall().then((data) => (this.products = data));
},
onRowExpand(event) { onRowExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000 }); this.$toast.add({ severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000 });
}, },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,32 +2,34 @@
<DocSectionText v-bind="$attrs"> <DocSectionText v-bind="$attrs">
<p>Cell Editing with Sorting and Filter</p> <p>Cell Editing with Sorting and Filter</p>
</DocSectionText> </DocSectionText>
<div class="card p-fluid"> <DeferredDemo @load="loadDemoData">
<DataTable <div class="card p-fluid">
v-model:filters="filters" <DataTable
:value="products" v-model:filters="filters"
editMode="cell" :value="products"
@cell-edit-complete="onCellEditComplete" editMode="cell"
filterDisplay="row" @cell-edit-complete="onCellEditComplete"
:pt="{ filterDisplay="row"
table: { style: 'min-width: 50rem' }, :pt="{
column: { table: { style: 'min-width: 50rem' },
bodycell: ({ state }) => ({ column: {
class: [{ 'pt-0 pb-0': state['d_editing'] }] 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 }"> <Column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%" sortable filter>
<InputText v-model="filterModel.value" v-tooltip.top.focus="'Hit enter key to filter'" type="text" @keydown.enter="filterCallback()" class="p-column-filter" /> <template #filter="{ filterModel, filterCallback }">
</template> <InputText v-model="filterModel.value" v-tooltip.top.focus="'Hit enter key to filter'" type="text" @keydown.enter="filterCallback()" class="p-column-filter" />
<template #editor="{ data, field }"> </template>
<InputText v-model="data[field]" autofocus /> <template #editor="{ data, field }">
</template> <InputText v-model="data[field]" autofocus />
</Column> </template>
</DataTable> </Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" /> <DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" />
</template> </template>
@ -271,10 +273,10 @@ const isPositiveInteger = (val) => {
{ field: 'price', header: 'Price' } { field: 'price', header: 'Price' }
]; ];
}, },
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onCellEditComplete(event) { onCellEditComplete(event) {
let { data, newValue, field } = 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. <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> </p>
</DocSectionText> </DocSectionText>
<div class="card p-fluid"> <DeferredDemo @load="loadDemoData">
<DataTable <div class="card p-fluid">
v-model:editingRows="editingRows" <DataTable
:value="products" v-model:editingRows="editingRows"
editMode="row" :value="products"
dataKey="id" editMode="row"
@row-edit-save="onRowEditSave" dataKey="id"
:pt="{ @row-edit-save="onRowEditSave"
table: { style: 'min-width: 50rem' }, :pt="{
column: { table: { style: 'min-width: 50rem' },
bodycell: ({ state }) => ({ column: {
style: state['d_editing'] && 'padding-top: 0.6rem; padding-bottom: 0.6rem' 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 }"> <Column field="code" header="Code" style="width: 20%">
<InputText v-model="data[field]" /> <template #editor="{ data, field }">
</template> <InputText v-model="data[field]" />
</Column> </template>
<Column field="name" header="Name" style="width: 20%"> </Column>
<template #editor="{ data, field }"> <Column field="name" header="Name" style="width: 20%">
<InputText v-model="data[field]" /> <template #editor="{ data, field }">
</template> <InputText v-model="data[field]" />
</Column> </template>
<Column field="inventoryStatus" header="Status" style="width: 20%"> </Column>
<template #editor="{ data, field }"> <Column field="inventoryStatus" header="Status" style="width: 20%">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status"> <template #editor="{ data, field }">
<template #option="slotProps"> <Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<Tag :value="slotProps.option.value" :severity="getStatusLabel(slotProps.option.value)" /> <template #option="slotProps">
</template> <Tag :value="slotProps.option.value" :severity="getStatusLabel(slotProps.option.value)" />
</Dropdown> </template>
</template> </Dropdown>
<template #body="slotProps"> </template>
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" /> <template #body="slotProps">
</template> <Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</Column> </template>
<Column field="price" header="Price" style="width: 20%"> </Column>
<template #body="{ data, field }"> <Column field="price" header="Price" style="width: 20%">
{{ formatCurrency(data[field]) }} <template #body="{ data, field }">
</template> {{ formatCurrency(data[field]) }}
<template #editor="{ data, field }"> </template>
<InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" /> <template #editor="{ data, field }">
</template> <InputNumber v-model="data[field]" mode="currency" currency="USD" locale="en-US" />
</Column> </template>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column> </Column>
</DataTable> <Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" /> <DocSectionCode :code="code" :service="['ProductService']" :dependencies="{ sass: '1.45.0', 'sass-loader': '8.0.2' }" />
</template> </template>
@ -77,7 +79,7 @@ export default {
table: { style: 'min-width: 50rem' }, table: { style: 'min-width: 50rem' },
column: { column: {
bodycell: ({ state }) => ({ 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' }, table: { style: 'min-width: 50rem' },
column: { column: {
bodycell: ({ state }) => ({ 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' }, table: { style: 'min-width: 50rem' },
column: { column: {
bodycell: ({ state }) => ({ 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: { methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowEditSave(event) { onRowEditSave(event) {
let { newData, index } = event; let { newData, index } = event;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,46 +5,48 @@
<i>rowgroup-collapse</i> events. <i>rowgroup-collapse</i> events.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable <div class="card">
v-model:expandedRowGroups="expandedRowGroups" <DataTable
:value="customers" v-model:expandedRowGroups="expandedRowGroups"
expandableRowGroups :value="customers"
rowGroupMode="subheader" expandableRowGroups
groupRowsBy="representative.name" rowGroupMode="subheader"
sortMode="single" groupRowsBy="representative.name"
sortField="representative.name" sortMode="single"
:sortOrder="1" sortField="representative.name"
@rowgroup-expand="onRowGroupExpand" :sortOrder="1"
@rowgroup-collapse="onRowGroupCollapse" @rowgroup-expand="onRowGroupExpand"
tableStyle="min-width: 50rem" @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" /> <template #groupheader="slotProps">
<span class="vertical-align-middle ml-2 font-bold line-height-3">{{ slotProps.data.representative.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" class="ml-2" />
</template> <span class="vertical-align-middle ml-2 font-bold line-height-3">{{ slotProps.data.representative.name }}</span>
<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> </template>
</Column> <Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company" style="width: 20%"></Column> <Column field="name" header="Name" style="width: 20%"></Column>
<Column field="status" header="Status" style="width: 20%"> <Column field="country" header="Country" style="width: 20%">
<template #body="slotProps"> <template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" /> <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> </template>
</Column> </DataTable>
<Column field="date" header="Date" style="width: 20%"></Column> </div>
<template #groupfooter="slotProps"> </DeferredDemo>
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
</div>
<DocSectionCode :code="code" :service="['CustomerService']" /> <DocSectionCode :code="code" :service="['CustomerService']" />
</template> </template>
@ -240,7 +242,7 @@ const calculateCustomerTotal = (name) => {
} }
} }
} }
return total; return total;
}; };
const getSeverity = (status) => { const getSeverity = (status) => {
@ -286,10 +288,10 @@ const getSeverity = (status) => {
} }
}; };
}, },
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: { methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
onRowGroupExpand(event) { onRowGroupExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000 }); 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"> <DocSectionText v-bind="$attrs">
<p>When <i>rowGroupMode</i> is configured to be <i>rowspan</i>, the grouping column spans multiple rows.</p> <p>When <i>rowGroupMode</i> is configured to be <i>rowspan</i>, the grouping column spans multiple rows.</p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" tableStyle="min-width: 50rem"> <div class="card">
<Column header="#" headerStyle="width:3rem"> <DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" tableStyle="min-width: 50rem">
<template #body="slotProps"> <Column header="#" headerStyle="width:3rem">
{{ slotProps.index + 1 }} <template #body="slotProps">
</template> {{ slotProps.index + 1 }}
</Column> </template>
<Column field="representative.name" header="Representative" style="min-width: 200px"> </Column>
<template #body="slotProps"> <Column field="representative.name" header="Representative" style="min-width: 200px">
<div class="flex align-items-center gap-2"> <template #body="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" /> <div class="flex align-items-center gap-2">
<span>{{ slotProps.data.representative.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" />
</div> <span>{{ slotProps.data.representative.name }}</span>
</template> </div>
</Column> </template>
<Column field="name" header="Name" style="min-width: 200px"></Column> </Column>
<Column field="country" header="Country" style="min-width: 150px"> <Column field="name" header="Name" style="min-width: 200px"></Column>
<template #body="slotProps"> <Column field="country" header="Country" style="min-width: 150px">
<div class="flex align-items-center gap-2"> <template #body="slotProps">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" /> <div class="flex align-items-center gap-2">
<span>{{ slotProps.data.country.name }}</span> <img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
</div> <span>{{ slotProps.data.country.name }}</span>
</template> </div>
</Column> </template>
<Column field="company" header="Company" style="min-width: 200px"></Column> </Column>
<Column field="status" header="Status" style="min-width: 100px"> <Column field="company" header="Company" style="min-width: 200px"></Column>
<template #body="slotProps"> <Column field="status" header="Status" style="min-width: 100px">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" /> <template #body="slotProps">
</template> <Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</Column> </template>
<Column field="date" header="Date" style="min-width: 100px"></Column> </Column>
</DataTable> <Column field="date" header="Date" style="min-width: 100px"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" /> <DocSectionCode :code="code" :service="['CustomerService']" />
</template> </template>
@ -242,10 +244,10 @@ const getSeverity = (status) => {
} }
}; };
}, },
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: { methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
onRowGroupExpand(event) { onRowGroupExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000 }); 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. with <i>groupfooter</i> slots.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem"> <div class="card">
<template #groupheader="slotProps"> <DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<div class="flex align-items-center gap-2"> <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" />
<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">
<div class="flex align-items-center gap-2"> <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" /> <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.country.name }}</span> <span>{{ slotProps.data.representative.name }}</span>
</div> </div>
</template> </template>
</Column> <Column field="representative.name" header="Representative"></Column>
<Column field="company" header="Company" style="min-width: 200px"></Column> <Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"> <Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps"> <template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" /> <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> </template>
</Column> </DataTable>
<Column field="date" header="Date" style="min-width: 200px"></Column> </div>
<template #groupfooter="slotProps"> </DeferredDemo>
<div class="flex justify-content-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
</div>
<DocSectionCode :code="code" :service="['CustomerService']" /> <DocSectionCode :code="code" :service="['CustomerService']" />
</template> </template>
@ -214,7 +216,7 @@ const calculateCustomerTotal = (name) => {
} }
} }
} }
return total; return total;
}; };
const getSeverity = (status) => { const getSeverity = (status) => {
@ -260,10 +262,10 @@ const getSeverity = (status) => {
} }
}; };
}, },
mounted() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: { methods: {
loadDemoData() {
CustomerService.getCustomersMedium().then((data) => (this.customers = data));
},
calculateCustomerTotal(name) { calculateCustomerTotal(name) {
let total = 0; 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>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> <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> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem"> <div class="card">
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column> <DataTable v-model:selection="selectedProduct" :value="products" dataKey="id" tableStyle="min-width: 50rem">
<Column field="code" header="Code"></Column> <Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
<Column field="name" header="Name"></Column> <Column field="code" header="Code"></Column>
<Column field="category" header="Category"></Column> <Column field="name" header="Name"></Column>
<Column field="quantity" header="Quantity"></Column> <Column field="category" header="Category"></Column>
</DataTable> <Column field="quantity" header="Quantity"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -109,8 +111,10 @@ const metaKey = ref(true);
} }
}; };
}, },
mounted() { methods: {
ProductService.getProductsMini().then((data) => (this.products = data)); loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
} }
}; };
</script> </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. <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> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<div class="flex justify-content-center align-items-center mb-4 gap-2"> <div class="card">
<InputSwitch v-model="metaKey" inputId="input-metakey" /> <div class="flex justify-content-center align-items-center mb-4 gap-2">
<label for="input-metakey">MetaKey</label> <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> </div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="multiple" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem"> </DeferredDemo>
<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>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -121,8 +123,10 @@ const metaKey = ref(true);
} }
}; };
}, },
mounted() { methods: {
ProductService.getProductsMini().then((data) => (this.products = data)); loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
} }
}; };
</script> </script>

View File

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

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs"> <DocSectionText v-bind="$attrs">
<p>DataTable provides <i>row-select</i> and <i>row-unselect</i> events to listen selection events.</p> <p>DataTable provides <i>row-select</i> and <i>row-unselect</i> events to listen selection events.</p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" dataKey="id" :metaKeySelection="false" @rowSelect="onRowSelect" @rowUnselect="onRowUnselect" tableStyle="min-width: 50rem"> <div class="card">
<Column field="code" header="Code"></Column> <DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" dataKey="id" :metaKeySelection="false" @rowSelect="onRowSelect" @rowUnselect="onRowUnselect" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column> <Column field="code" header="Code"></Column>
<Column field="category" header="Category"></Column> <Column field="name" header="Name"></Column>
<Column field="quantity" header="Quantity"></Column> <Column field="category" header="Category"></Column>
</DataTable> <Column field="quantity" header="Quantity"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -124,10 +126,10 @@ const onRowUnselect = (event) => {
} }
}; };
}, },
mounted() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
methods: { methods: {
loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
},
onRowSelect(event) { onRowSelect(event) {
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000 }); 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. setting it to false.
</p> </p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<div class="flex justify-content-center align-items-center mb-4 gap-2"> <div class="card">
<InputSwitch v-model="metaKey" inputId="input-metakey" /> <div class="flex justify-content-center align-items-center mb-4 gap-2">
<label for="input-metakey">MetaKey</label> <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> </div>
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :metaKeySelection="metaKey" dataKey="id" tableStyle="min-width: 50rem"> </DeferredDemo>
<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>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -125,8 +127,10 @@ const metaKey = ref(true);
} }
}; };
}, },
mounted() { methods: {
ProductService.getProductsMini().then((data) => (this.products = data)); loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
} }
}; };
</script> </script>

View File

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

View File

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

View File

@ -8,7 +8,7 @@
<div class="card flex justify-content-center"> <div class="card flex justify-content-center">
<Button label="Show" icon="pi pi-external-link" @click="dialogVisible = true" /> <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"> <DataTable :value="customers" scrollable scrollHeight="flex" tableStyle="min-width: 50rem">
<Column field="name" header="Name"></Column> <Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column> <Column field="country.name" header="Country"></Column>
@ -140,10 +140,12 @@ onMounted(() => {
} }
}; };
}, },
mounted() { methods: {
CustomerService.getCustomersMedium().then((data) => { onShow() {
this.customers = data; CustomerService.getCustomersMedium().then((data) => {
}); this.customers = data;
});
}
} }
}; };
</script> </script>

View File

@ -2,26 +2,28 @@
<DocSectionText v-bind="$attrs"> <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> <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> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Balance" offLabel="Balance" /> <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"> <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="name" header="Name" style="min-width: 200px" frozen class="font-bold"></Column>
<Column field="id" header="Id" style="min-width: 100px"></Column> <Column field="id" header="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column> <Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" 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="date" header="Date" style="min-width: 200px"></Column>
<Column field="company" header="Company" 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="status" header="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" 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="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen"> <Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }"> <template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span> <span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template> </template>
</Column> </Column>
</DataTable> </DataTable>
</div> </div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CustomerService']" /> <DocSectionCode :code="code" :service="['CustomerService']" />
</template> </template>
@ -165,12 +167,12 @@ const formatCurrency = (value) => {
} }
}; };
}, },
mounted() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = data;
});
},
methods: { methods: {
loadDemoData() {
CustomerService.getCustomersLarge().then((data) => {
this.customers = data;
});
},
formatCurrency(value) { formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
} }

View File

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

View File

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

View File

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

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs"> <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> <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> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="products" sortMode="multiple" tableStyle="min-width: 50rem"> <div class="card">
<Column field="code" header="Code" sortable style="width: 25%"></Column> <DataTable :value="products" sortMode="multiple" tableStyle="min-width: 50rem">
<Column field="name" header="Name" sortable style="width: 25%"></Column> <Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column> <Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column> <Column field="category" header="Category" sortable style="width: 25%"></Column>
</DataTable> <Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -98,8 +100,10 @@ const products = ref();
} }
}; };
}, },
mounted() { methods: {
ProductService.getProductsMini().then((data) => (this.products = data)); loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
} }
}; };
</script> </script>

View File

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

View File

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

View File

@ -2,14 +2,16 @@
<DocSectionText v-bind="$attrs"> <DocSectionText v-bind="$attrs">
<p>Sorting on a column is enabled by adding the <i>sortable</i> property.</p> <p>Sorting on a column is enabled by adding the <i>sortable</i> property.</p>
</DocSectionText> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable :value="products" tableStyle="min-width: 50rem"> <div class="card">
<Column field="code" header="Code" sortable style="width: 25%"></Column> <DataTable :value="products" tableStyle="min-width: 50rem">
<Column field="name" header="Name" sortable style="width: 25%"></Column> <Column field="code" header="Code" sortable style="width: 25%"></Column>
<Column field="category" header="Category" sortable style="width: 25%"></Column> <Column field="name" header="Name" sortable style="width: 25%"></Column>
<Column field="quantity" header="Quantity" sortable style="width: 25%"></Column> <Column field="category" header="Category" sortable style="width: 25%"></Column>
</DataTable> <Column field="quantity" header="Quantity" sortable style="width: 25%"></Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['ProductService']" /> <DocSectionCode :code="code" :service="['ProductService']" />
</template> </template>
@ -98,8 +100,10 @@ const products = ref();
} }
}; };
}, },
mounted() { methods: {
ProductService.getProductsMini().then((data) => (this.products = data)); loadDemoData() {
ProductService.getProductsMini().then((data) => (this.products = data));
}
} }
}; };
</script> </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>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> <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> </DocSectionText>
<div class="card"> <DeferredDemo @load="loadDemoData">
<DataTable <div class="card">
:value="virtualCars" <DataTable
scrollable :value="virtualCars"
scrollHeight="400px" scrollable
:virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }" scrollHeight="400px"
tableStyle="min-width: 50rem" :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> <Column field="id" header="Id" style="width: 20%">
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }"> <template #loading>
<Skeleton width="60%" height="1rem" /> <div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
</div> <Skeleton width="60%" height="1rem" />
</template> </div>
</Column> </template>
<Column field="vin" header="Vin" style="width: 20%"> </Column>
<template #loading> <Column field="vin" header="Vin" style="width: 20%">
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }"> <template #loading>
<Skeleton width="40%" height="1rem" /> <div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
</div> <Skeleton width="40%" height="1rem" />
</template> </div>
</Column> </template>
<Column field="year" header="Year" style="width: 20%"> </Column>
<template #loading> <Column field="year" header="Year" style="width: 20%">
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }"> <template #loading>
<Skeleton width="30%" height="1rem" /> <div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
</div> <Skeleton width="30%" height="1rem" />
</template> </div>
</Column> </template>
<Column field="brand" header="Brand" style="width: 20%"> </Column>
<template #loading> <Column field="brand" header="Brand" style="width: 20%">
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }"> <template #loading>
<Skeleton width="40%" height="1rem" /> <div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
</div> <Skeleton width="40%" height="1rem" />
</template> </div>
</Column> </template>
<Column field="color" header="Color" style="width: 20%"> </Column>
<template #loading> <Column field="color" header="Color" style="width: 20%">
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }"> <template #loading>
<Skeleton width="60%" height="1rem" /> <div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
</div> <Skeleton width="60%" height="1rem" />
</template> </div>
</Column> </template>
</DataTable> </Column>
</div> </DataTable>
</div>
</DeferredDemo>
<DocSectionCode :code="code" :service="['CarService']" /> <DocSectionCode :code="code" :service="['CarService']" />
</template> </template>
@ -280,10 +282,10 @@ const loadCarsLazy = (event) => {
} }
}; };
}, },
mounted() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
},
methods: { methods: {
loadDemoData() {
this.cars = Array.from({ length: 100000 }).map((_, i) => CarService.generateCar(i + 1));
},
loadCarsLazy(event) { loadCarsLazy(event) {
!this.lazyLoading && (this.lazyLoading = true); !this.lazyLoading && (this.lazyLoading = true);

View File

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

View File

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