Row expansion demo

pull/358/head
cagataycivici 2020-07-01 11:55:56 +03:00
parent 0d881a1ad9
commit f52e5fd2c6
12 changed files with 514 additions and 100 deletions

View File

@ -0,0 +1,341 @@
{
"data": [
{
"id": "1000",
"code": "f230fh0g3",
"name": "Bamboo Watch",
"description": "Product Description",
"image": "bamboo-watch.jpg",
"price": 65,
"category": "Accessories",
"quantity": 24,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": [
{
"id": "1000",
"productCode": "f230fh0g3",
"date": "2020-09-13",
"amount": 65,
"quantity": 1,
"customer": "David James",
"status": "PENDING"
},
{
"id": "1001",
"productCode": "f230fh0g3",
"date": "2020-05-14",
"amount": 130,
"quantity": 2,
"customer": "Leon Rodrigues",
"status": "DELIVERED"
},
{
"id": "1002",
"productCode": "f230fh0g3",
"date": "2019-01-04",
"amount": 65,
"quantity": 1,
"customer": "Juan Alejandro",
"status": "RETURNED"
},
{
"id": "1003",
"productCode": "f230fh0g3",
"date": "2020-09-13",
"amount": 195,
"quantity": 3,
"customer": "Claire Morrow",
"status": "CANCELLED"
}
]
},
{
"id": "1001",
"code": "nvklal433",
"name": "Black Watch",
"description": "Product Description",
"image": "black-watch.jpg",
"price": 72,
"category": "Accessories",
"quantity": 61,
"inventoryStatus": "INSTOCK",
"rating": 4,
"orders": [
{
"id": "2000",
"productCode": "nvklal433",
"date": "2020-05-14",
"amount": 72,
"quantity": 1,
"customer": "Maisha Jefferson",
"status": "DELIVERED"
},
{
"id": "2001",
"productCode": "nvklal433",
"date": "2020-02-28",
"amount": 144,
"quantity": 2,
"customer": "Octavia Murillo",
"status": "PENDING"
}
]
},
{
"id": "1002",
"code": "zz21cz3c1",
"name": "Blue Band",
"description": "Product Description",
"image": "blue-band.jpg",
"price": 79,
"category": "Fitness",
"quantity": 2,
"inventoryStatus": "LOWSTOCK",
"rating": 3,
"orders": [
{
"id": "3000",
"productCode": "zz21cz3c1",
"date": "2020-07-05",
"amount": 79,
"quantity": 1,
"customer": "Stacey Leja",
"status": "DELIVERED"
},
{
"id": "3001",
"productCode": "zz21cz3c1",
"date": "2020-02-06",
"amount": 79,
"quantity": 1,
"customer": "Ashley Wickens",
"status": "DELIVERED"
}
]
},
{
"id": "1003",
"code": "244wgerg2",
"name": "Blue T-Shirt",
"description": "Product Description",
"image": "blue-t-shirt.jpg",
"price": 29,
"category": "Clothing",
"quantity": 25,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": []
},
{
"id": "1004",
"code": "h456wer53",
"name": "Bracelet",
"description": "Product Description",
"image": "bracelet.jpg",
"price": 15,
"category": "Accessories",
"quantity": 73,
"inventoryStatus": "INSTOCK",
"rating": 4,
"orders": [
{
"id": "5000",
"productCode": "h456wer53",
"date": "2020-09-05",
"amount": 60,
"quantity": 4,
"customer": "Mayumi Misaki",
"status": "PENDING"
},
{
"id": "5001",
"productCode": "h456wer53",
"date": "2019-04-16",
"amount": 2,
"quantity": 30,
"customer": "Francesco Salvatore",
"status": "DELIVERED"
}
]
},
{
"id": "1005",
"code": "av2231fwg",
"name": "Brown Purse",
"description": "Product Description",
"image": "brown-purse.jpg",
"price": 120,
"category": "Accessories",
"quantity": 0,
"inventoryStatus": "OUTOFSTOCK",
"rating": 4,
"orders": [
{
"id": "6000",
"productCode": "av2231fwg",
"date": "2020-01-25",
"amount": 120,
"quantity": 1,
"customer": "Isabel Sinclair",
"status": "RETURNED"
},
{
"id": "6001",
"productCode": "av2231fwg",
"date": "2019-03-12",
"amount": 240,
"quantity": 2,
"customer": "Lionel Clifford",
"status": "DELIVERED"
},
{
"id": "6002",
"productCode": "av2231fwg",
"date": "2019-05-05",
"amount": 120,
"quantity": 1,
"customer": "Cody Chavez",
"status": "DELIVERED"
}
]
},
{
"id": "1006",
"code": "bib36pfvm",
"name": "Chakra Bracelet",
"description": "Product Description",
"image": "chakra-bracelet.jpg",
"price": 32,
"category": "Accessories",
"quantity": 5,
"inventoryStatus": "LOWSTOCK",
"rating": 3,
"orders": [
{
"id": "7000",
"productCode": "bib36pfvm",
"date": "2020-02-24",
"amount": 32,
"quantity": 1,
"customer": "Arvin Darci",
"status": "DELIVERED"
},
{
"id": "7001",
"productCode": "bib36pfvm",
"date": "2020-01-14",
"amount": 64,
"quantity": 2,
"customer": "Izzy Jones",
"status": "PENDING"
}
]
},
{
"id": "1007",
"code": "mbvjkgip5",
"name": "Galaxy Earrings",
"description": "Product Description",
"image": "galaxy-earrings.jpg",
"price": 34,
"category": "Accessories",
"quantity": 23,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": [
{
"id": "8000",
"productCode": "mbvjkgip5",
"date": "2020-06-19",
"amount": 34,
"quantity": 1,
"customer": "Jennifer Smith",
"status": "DELIVERED"
}
]
},
{
"id": "1008",
"code": "vbb124btr",
"name": "Game Controller",
"description": "Product Description",
"image": "game-controller.jpg",
"price": 99,
"category": "Electronics",
"quantity": 2,
"inventoryStatus": "LOWSTOCK",
"rating": 4,
"orders": [
{
"id": "9000",
"productCode": "vbb124btr",
"date": "2020-01-05",
"amount": 99,
"quantity": 1,
"customer": "Jeanfrancois David",
"status": "DELIVERED"
},
{
"id": "9001",
"productCode": "vbb124btr",
"date": "2020-01-19",
"amount": 198,
"quantity": 2,
"customer": "Ivar Greenwood",
"status": "RETURNED"
}
]
},
{
"id": "1009",
"code": "cm230f032",
"name": "Gaming Set",
"description": "Product Description",
"image": "gaming-set.jpg",
"price": 299,
"category": "Electronics",
"quantity": 63,
"inventoryStatus": "INSTOCK",
"rating": 3,
"orders": [
{
"id": "10000",
"productCode": "cm230f032",
"date": "2020-06-24",
"amount": 299,
"quantity": 1,
"customer": "Kadeem Mujtaba",
"status": "PENDING"
},
{
"id": "10001",
"productCode": "cm230f032",
"date": "2020-05-11",
"amount": 299,
"quantity": 1,
"customer": "Ashley Wickens",
"status": "DELIVERED"
},
{
"id": "10002",
"productCode": "cm230f032",
"date": "2019-02-07",
"amount": 299,
"quantity": 1,
"customer": "Julie Johnson",
"status": "DELIVERED"
},
{
"id": "10003",
"productCode": "cm230f032",
"date": "2020-04-26",
"amount": 299,
"quantity": 1,
"customer": "Tony Costa",
"status": "CANCELLED"
}
]
}
]
}

View File

@ -61,6 +61,35 @@
}
}
.order-badge {
border-radius: 2px;
padding: .25em .5rem;
text-transform: uppercase;
font-weight: 700;
font-size: 12px;
letter-spacing: .3px;
&.order-delivered {
background: #C8E6C9;
color: #256029;
}
&.order-cancelled {
background: #FFCDD2;
color: #C63737;
}
&.order-pending {
background: #FEEDAF;
color: #8A5340;
}
&.order-returned {
background: #ECCFFF;
color: #694382;
}
}
.image-text {
vertical-align: middle;
margin-left: .5rem;

View File

@ -8,5 +8,9 @@ export default class ProductService {
getProducts() {
return axios.get('demo/data/products.json').then(res => res.data.data);
}
getProductsWithOrdersSmall() {
return axios.get('demo/data/products-orders-small.json').then(res => res.data.data);
}
}

View File

@ -18,7 +18,7 @@
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Expand Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="expand">

View File

@ -265,7 +265,7 @@ export default {
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';
@ -379,7 +379,7 @@ export default {
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';

View File

@ -239,11 +239,11 @@ export default {
let month = date.getMonth() + 1;
let day = date.getDate();
if (month < 10) {
if (month &lt; 10) {
month = '0' + month;
}
if (day < 10) {
if (day &lt; 10) {
day = '0' + day;
}

View File

@ -10,7 +10,7 @@
<div class="content-section implementation">
<div class="card">
<DataTable :value="customers" :paginator="true" :rows="10"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rowsPerPageOptions="[10,20,50]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}">
<Column field="name" header="Name"></Column>
@ -33,7 +33,7 @@
<CodeHighlight>
<template v-pre>
&lt;DataTable :value="customers" :paginator="true" :rows="10"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rowsPerPageOptions="[10,20,50]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"&gt;
&lt;Column field="name" header="Name"&gt;&lt;/Column&gt;

View File

@ -9,31 +9,60 @@
<div class="content-section implementation">
<div class="card">
<DataTable :value="cars" :expandedRows.sync="expandedRows" dataKey="vin"
<DataTable :value="products" :expandedRows.sync="expandedRows" dataKey="id"
@row-expand="onRowExpand" @row-collapse="onRowCollapse">
<template #header>
<div class="table-header-container">
<Button icon="pi pi-plus" label="Expand All" @click="expandAll" />
<Button icon="pi pi-plus" label="Expand All" @click="expandAll" class="p-mr-2" />
<Button icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column :expander="true" headerStyle="width: 3em" />
<Column field="vin" header="Vin"></Column>
<Column field="year" header="Year"></Column>
<Column field="brand" header="Brand"></Column>
<Column field="color" header="Color"></Column>
<Column :expander="true" headerStyle="width: 3rem" />
<Column field="name" header="Name" sortable></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price" sortable>
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
<Column field="category" header="Category" sortable></Column>
<Column field="rating" header="Reviews" sortable>
<template #body="slotProps">
<Rating :value="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column header="Status" sortable>
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<template #expansion="slotProps">
<div class="car-details">
<div>
<img :src="'demo/images/car/' + slotProps.data.brand + '.png'" :alt="slotProps.data.brand"/>
<div class="p-grid">
<div class="p-col-12">Vin: <b>{{slotProps.data.vin}}</b></div>
<div class="p-col-12">Year: <b>{{slotProps.data.year}}</b></div>
<div class="p-col-12">Brand: <b>{{slotProps.data.brand}}</b></div>
<div class="p-col-12">Color: <b>{{slotProps.data.color}}</b></div>
</div>
</div>
<Button icon="pi pi-search"></Button>
<div class="orders-subtable">
<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" sortable>
{{formatCurrency(slotProps.data.amount)}}
</template>
</Column>
<Column header="Status" sortable>
<template #body="slotProps">
<span :class="'order-badge order-' + slotProps.data.status.toLowerCase()">{{slotProps.data.status}}</span>
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
@ -45,31 +74,60 @@
<TabPanel header="Source">
<CodeHighlight>
<template v-pre>
&lt;DataTable :value="cars" :expandedRows.sync="expandedRows" dataKey="vin"
&lt;DataTable :value="products" :expandedRows.sync="expandedRows" dataKey="id"
@row-expand="onRowExpand" @row-collapse="onRowCollapse"&gt;
&lt;template #header&gt;
&lt;div class="table-header-container"&gt;
&lt;Button icon="pi pi-plus" label="Expand All" @click="expandAll" /&gt;
&lt;Button icon="pi pi-plus" label="Expand All" @click="expandAll" class="p-mr-2" /&gt;
&lt;Button icon="pi pi-minus" label="Collapse All" @click="collapseAll" /&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;Column :expander="true" headerStyle="width: 3em" /&gt;
&lt;Column field="vin" header="Vin"&gt;&lt;/Column&gt;
&lt;Column field="year" header="Year"&gt;&lt;/Column&gt;
&lt;Column field="brand" header="Brand"&gt;&lt;/Column&gt;
&lt;Column field="color" header="Color"&gt;&lt;/Column&gt;
&lt;Column :expander="true" headerStyle="width: 3rem" /&gt;
&lt;Column field="name" header="Name" sortable&gt;&lt;/Column&gt;
&lt;Column header="Image"&gt;
&lt;template #body="slotProps"&gt;
&lt;img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="product-image" /&gt;
&lt;/template&gt;
&lt;/Column&gt;
&lt;Column field="price" header="Price" sortable&gt;
&lt;template #body="slotProps"&gt;
{{formatCurrency(slotProps.data.price)}}
&lt;/template&gt;
&lt;/Column&gt;
&lt;Column field="category" header="Category" sortable&gt;&lt;/Column&gt;
&lt;Column field="rating" header="Reviews" sortable&gt;
&lt;template #body="slotProps"&gt;
&lt;Rating :value="slotProps.data.rating" :readonly="true" :cancel="false" /&gt;
&lt;/template&gt;
&lt;/Column&gt;
&lt;Column header="Status" sortable&gt;
&lt;template #body="slotProps"&gt;
&lt;span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()"&gt;{{slotProps.data.inventoryStatus}}&lt;/span&gt;
&lt;/template&gt;
&lt;/Column&gt;
&lt;template #expansion="slotProps"&gt;
&lt;div class="car-details"&gt;
&lt;div&gt;
&lt;img :src="'demo/images/car/' + slotProps.data.brand + '.png'" :alt="slotProps.data.brand"/&gt;
&lt;div class="p-grid"&gt;
&lt;div class="p-col-12"&gt;Vin: &lt;b&gt;&#123;&#123;slotProps.data.vin&#125;&#125;&lt;/b&gt;&lt;/div&gt;
&lt;div class="p-col-12"&gt;Year: &lt;b&gt;&#123;&#123;slotProps.data.year&#125;&#125;&lt;/b&gt;&lt;/div&gt;
&lt;div class="p-col-12"&gt;Brand: &lt;b&gt;&#123;&#123;slotProps.data.brand&#125;&#125;&lt;/b&gt;&lt;/div&gt;
&lt;div class="p-col-12"&gt;Color: &lt;b&gt;&#123;&#123;slotProps.data.color&#125;&#125;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;Button icon="pi pi-search"&gt;&lt;/Button&gt;
&lt;div class="orders-subtable"&gt;
&lt;h5&gt;Orders for {{slotProps.data.name}}&lt;/h5&gt;
&lt;DataTable :value="slotProps.data.orders"&gt;
&lt;Column field="id" header="Id" sortable&gt;&lt;/Column&gt;
&lt;Column field="customer" header="Customer" sortable&gt;&lt;/Column&gt;
&lt;Column field="date" header="Date" sortable&gt;&lt;/Column&gt;
&lt;Column field="amount" header="Amount" sortable&gt;
&lt;template #body="slotProps" sortable&gt;
{{formatCurrency(slotProps.data.amount)}}
&lt;/template&gt;
&lt;/Column&gt;
&lt;Column header="Status" sortable&gt;
&lt;template #body="slotProps"&gt;
&lt;span :class="'order-badge order-' + slotProps.data.status.toLowerCase()"&gt;{{slotProps.data.status}}&lt;/span&gt;
&lt;/template&gt;
&lt;/Column&gt;
&lt;Column headerStyle="width:4rem"&gt;
&lt;template #body&gt;
&lt;Button icon="pi pi-search" /&gt;
&lt;/template&gt;
&lt;/Column&gt;
&lt;/DataTable&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/DataTable&gt;
@ -77,36 +135,39 @@
</CodeHighlight>
<CodeHighlight lang="javascript">
import CarService from '../../service/CarService';
import ProductService from '../../service/ProductService';
export default {
data() {
return {
cars: null,
products: null,
expandedRows: []
}
},
carService: null,
productService: null,
created() {
this.carService = new CarService();
this.productService = new ProductService();
},
mounted() {
this.carService.getCarsSmall().then(data => this.cars = data);
this.productService.getProductsWithOrdersSmall().then(data => this.products = data);
},
methods: {
onRowExpand(event) {
this.$toast.add({severity: 'info', summary: 'Row Expanded', detail: 'Vin: ' + event.data.vin, life: 3000});
this.$toast.add({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
},
onRowCollapse(event) {
this.$toast.add({severity: 'success', summary: 'Row Collapsed', detail: 'Vin: ' + event.data.vin, life: 3000});
this.$toast.add({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
},
expandAll() {
this.expandedRows = this.cars.filter(car => car.vin);
this.expandedRows = this.products.filter(p => p.id);
this.$toast.add({severity: 'success', summary: 'All Rows Expanded', life: 3000});
},
collapseAll() {
this.expandedRows = null;
this.$toast.add({severity: 'success', summary: 'All Rows Collapsed', life: 3000});
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
@ -118,75 +179,51 @@ export default {
</template>
<script>
import CarService from '../../service/CarService';
import ProductService from '../../service/ProductService';
export default {
data() {
return {
cars: null,
products: null,
expandedRows: []
}
},
carService: null,
productService: null,
created() {
this.carService = new CarService();
this.productService = new ProductService();
},
mounted() {
this.carService.getCarsSmall().then(data => this.cars = data);
this.productService.getProductsWithOrdersSmall().then(data => this.products = data);
},
methods: {
onRowExpand(event) {
this.$toast.add({severity: 'info', summary: 'Row Expanded', detail: 'Vin: ' + event.data.vin, life: 3000});
this.$toast.add({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
},
onRowCollapse(event) {
this.$toast.add({severity: 'success', summary: 'Row Collapsed', detail: 'Vin: ' + event.data.vin, life: 3000});
this.$toast.add({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
},
expandAll() {
this.expandedRows = this.cars.filter(car => car.vin);
this.expandedRows = this.products.filter(p => p.id);
this.$toast.add({severity: 'success', summary: 'All Rows Expanded', life: 3000});
},
collapseAll() {
this.expandedRows = null;
this.$toast.add({severity: 'success', summary: 'All Rows Collapsed', life: 3000});
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
</script>
<style lang="scss" scoped>
.table-header-container {
text-align: left;
button {
min-width: 10rem;
&:first-child {
margin-right: .5rem;
}
}
.product-image {
width: 100px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
.car-details {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2rem;
& > div {
display: flex;
align-items: center;
img {
margin-right: 14px;
}
}
}
@media (max-width: 1024px) {
.car-details {
img {
width: 75px;
}
}
.orders-subtable {
padding: 1rem;
}
</style>

View File

@ -285,7 +285,7 @@ export default {
methods: {
loadChunk(index, length) {
let chunk = [];
for (let i = 0; i < length; i++) {
for (let i = 0; i &lt; length; i++) {
chunk[i] = {...this.inmemoryData[i]};
}

View File

@ -298,7 +298,6 @@ export default {
<script>
import CustomerService from '../../service/CustomerService';
import DataTableDoc from './DataTableDoc';
export default {
data() {

View File

@ -66,9 +66,11 @@ export default {
},
stockClass(data) {
return [
{'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity < 10,
'instock': data.quantity > 10}
{
'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 &amp;&amp; data.quantity &lt; 10,
'instock': data.quantity > 10
}
];
}
}
@ -125,9 +127,11 @@ export default {
},
stockClass(data) {
return [
{'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity < 10,
'instock': data.quantity > 10}
{
'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity<10,
'instock': data.quantity > 10
}
];
}
}

View File

@ -44,7 +44,7 @@
</DataTable>
</div>
</div>
<div class="content-section documentation">