chore: add nuxt 3 exmaples
This commit is contained in:
Родитель
8e58f33b86
Коммит
72934fa5fa
Двоичный файл не отображается.
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
title: Add a Tooltip to the TreeView Component
|
||||
description: An example about how to add the Native Toolbar to the Kendo UI for Vue Native TreeView component.
|
||||
type: how-to
|
||||
page_title: Add a Tooltip to the TreeView Component - Kendo UI for Vue Native Tooltip - Kendo UI for Vue Native TreeView
|
||||
slug: add-tooltip-to-treeview
|
||||
tags: tooltip, treeview, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.3.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
Learn how to add the [Tooltip](slug:overview_tooltip) component to the [TreeView](slug:overview_tooltip) in the Kendo UI for Vue Native suite.
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To display the Native `Tooltip` when hovering a node in the Native `TreeView`, you have to define a custom template for the TreeView items. The custom template of the TreeView can be defined through its [item](slug:api_treeview_treeviewprops#toc-item) property.
|
||||
|
||||
The runnable example in the next section below, uses the following template which is passed to the `item` prop of the TreeView.
|
||||
|
||||
```js
|
||||
<template v-slot:item="{ props }">
|
||||
<span :title="props.item.description">
|
||||
<span :class="iconClassName(props.item)" key="0" />
|
||||
{{ props.item.text }}
|
||||
</span>
|
||||
</template>
|
||||
```
|
||||
In the above template you can see that we are passing the value of the `description` dataItem field to the `title` attribute of the span element rendered in each item. Once we have a `title` attribute definition for each TreeView node, we only have to initialize the Tooltip as follows:
|
||||
|
||||
```js
|
||||
<Tooltip :position="'right'" :anchor-element="'target'">
|
||||
.............
|
||||
TreeView definition
|
||||
.............
|
||||
</Tooltip>
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:460 %}
|
||||
{% embed_file add-tooltip-to-treeview/main.vue preview %}
|
||||
{% embed_file add-tooltip-to-treeview/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Customize the Colors inside the DatePicker Popup
|
||||
description: An example on how you can customize the colors inside the popup of the Kendo UI for Vue Native DatePicker.
|
||||
type: how-to
|
||||
page_title: Customize the DatePicker Popup Colors - Kendo UI for Vue Native DatePicker
|
||||
slug: change-datepicker-popup-color
|
||||
tags: datepicker, popup, change, customize, color, kendovue
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.0.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
How to customize the colors of the different elements inside the popup of the Kendo UI for Vue Native DatePicker?
|
||||
|
||||
## Solution
|
||||
|
||||
Use the [`popup`](slug:api_dateinputs_datepickerprops#toc_popup) prop to pass a [`custom`](slug:custom_rendering_datepicker#toc-customizing-the-popup) popup template to the DatePicker.
|
||||
|
||||
In the custom popup template we should use the [`Popup`](slug:overview_popup) component and its [`popupClass`](slug:api_popup_popupprops#toc_popupclass) property.
|
||||
|
||||
Once the value of the `popupClass` property is defined, we can use this value to apply styles to the different DOM elements inside the popup. Here are the styles used in the below example:
|
||||
|
||||
```html
|
||||
<style>
|
||||
/* Set the background of the Popup */
|
||||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table {
|
||||
background-color: #8bc34a;
|
||||
}
|
||||
|
||||
/* Set the text color of the different elements inside the Popup */
|
||||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table thead,
|
||||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table td {
|
||||
color: #ffff00;
|
||||
}
|
||||
|
||||
/* Style the current date and the "Today" button */
|
||||
.inner-wrapper .k-calendar table td.k-today span.k-link,
|
||||
.inner-wrapper .k-calendar div.k-calendar-header span {
|
||||
color: #0000ff;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
{% meta id:index height:400 %}
|
||||
{% embed_file change-datepicker-popup-colors/main.vue preview %}
|
||||
{% embed_file change-datepicker-popup-colors/CustomPopup.vue %}
|
||||
{% embed_file change-datepicker-popup-colors/styles.css %}
|
||||
{% embed_file change-datepicker-popup-colors/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
title: Customize the Label Colors of a Donut Chart with Multiple Series
|
||||
description: An example on how to customize the labels of the a Kendo UI for Vue Native Donut Chart with multiple series.
|
||||
type: how-to
|
||||
page_title: Customize the Labels of a Donut Chart with Multiple Series - Kendo UI for Vue Native Chart
|
||||
slug: donut-chart-multiple-series-different-label-colors
|
||||
tags: chart, charts, native chart, donut, label, color, customize, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.3.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The current Knowledge base article uses this [Donut Chart - Displaying Multiple Series](slug:donut_seriestypes_charts#toc-displaying-multiple-series) demo as a basis and shows how you can customize the labels of a Donut Chart with multiple series.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
The customization of the `Donut Chart` series is based on the following function:
|
||||
```js
|
||||
labelVisual(e) {
|
||||
const defaultLabel = e.createVisual();
|
||||
const bbox = defaultLabel.bbox();
|
||||
const group = new Group();
|
||||
|
||||
group.append(
|
||||
new Text(e.dataItem.value, [bbox.origin.x, bbox.origin.y], {
|
||||
font: `bold 15px Arial`,
|
||||
fill: {
|
||||
color: e.dataItem.labelColor,
|
||||
},
|
||||
})
|
||||
);
|
||||
return group;
|
||||
}
|
||||
```
|
||||
The `labelColor` property defined in the dataItem of a Chart series item holds the color value we want for the Chart labels.
|
||||
|
||||
In addition, we have the following `seriesLabels` data property to which the above method is passed.
|
||||
```js
|
||||
seriesLabels: {
|
||||
visible: true,
|
||||
visual: this.labelVisual,
|
||||
}
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta height:500 %}
|
||||
{% embed_file donut-chart-multiple-series-different-label-colors/main.vue preview %}
|
||||
{% embed_file donut-chart-multiple-series-different-label-colors/main.js %}
|
||||
{% embed_file donut-chart-multiple-series-different-label-colors/donut-series-data.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,5 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<div>
|
||||
<Tooltip :position="'right'" :anchor-element="'target'">
|
||||
<TreeView
|
||||
:animate="false"
|
||||
:dataItems="tree"
|
||||
:expandIcons="true"
|
||||
:item="'item'"
|
||||
>
|
||||
<template v-slot:item="{ props }">
|
||||
<span :title="props.item.description">
|
||||
<span :class="iconClassName(props.item)" key="0" />
|
||||
{{ props.item.text }}
|
||||
</span>
|
||||
</template>
|
||||
</TreeView>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TreeView } from '@progress/kendo-vue-treeview';
|
||||
import { Tooltip } from '@progress/kendo-vue-tooltip';
|
||||
|
||||
const is = (fileName, ext) => new RegExp(`.${ext}\$`).test(fileName);
|
||||
export default {
|
||||
components: {
|
||||
TreeView,
|
||||
Tooltip,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tree: [
|
||||
{
|
||||
text: 'My Documents',
|
||||
description:
|
||||
'This is the "My Documents" folder and it is the "root" node of the TreeView',
|
||||
expanded: true,
|
||||
items: [
|
||||
{
|
||||
text: 'Kendo UI for Vue Project',
|
||||
description:
|
||||
'This is the "Kendo UI for Vue Project" folder. It contains the index.html, about.html and logo.png files.',
|
||||
expanded: true,
|
||||
items: [
|
||||
{
|
||||
text: 'about.html',
|
||||
description:
|
||||
'A file in the "Kendo UI for Vue Project" folder',
|
||||
},
|
||||
{
|
||||
text: 'index.html',
|
||||
description:
|
||||
'A file in the "Kendo UI for Vue Project" folder',
|
||||
},
|
||||
{
|
||||
text: 'logo.png',
|
||||
description:
|
||||
'A file in the "Kendo UI for Vue Project" folder',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'New Web Site',
|
||||
description:
|
||||
'This is the "New Web Site" folder. It contains the mockup.jpg and Research.pdf files.',
|
||||
expanded: true,
|
||||
items: [
|
||||
{
|
||||
text: 'mockup.jpg',
|
||||
description: 'A file in the "New Web Site" folder',
|
||||
},
|
||||
{
|
||||
text: 'Research.pdf',
|
||||
description: 'A file in the "New Web Site" folder',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Reports',
|
||||
description:
|
||||
'This is a long text description. Demonstarating how the Tooltip handles a long texts. This is a long text description. Demonstarating how the Tooltip handles a long texts. This is a long text description. Demonstarating how the Tooltip handles a long texts.This is a long text description. Demonstarating how the Tooltip handles a long texts.',
|
||||
expanded: true,
|
||||
items: [
|
||||
{
|
||||
text: 'February.pdf',
|
||||
description: 'February.pdf file ',
|
||||
},
|
||||
{
|
||||
text: 'March.pdf',
|
||||
description: 'March.pdf file ',
|
||||
},
|
||||
{
|
||||
text: 'April.pdf',
|
||||
description: 'April.pdf file ',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
filterElements(element) {
|
||||
console.log(element.className === 'k-treeview-leaf');
|
||||
if (element.className === 'k-treeview-leaf') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
iconClassName({ text, items }) {
|
||||
if (items !== undefined) {
|
||||
return 'k-icon k-i-folder';
|
||||
} else if (is(text, 'pdf')) {
|
||||
return 'k-icon k-i-file-pdf';
|
||||
} else if (is(text, 'html')) {
|
||||
return 'k-icon k-i-html';
|
||||
} else if (is(text, 'jpg|png')) {
|
||||
return 'k-icon k-i-image';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<Popup
|
||||
:anchor="'datepicker'"
|
||||
:show="show"
|
||||
:popup-class="'inner-wrapper'"
|
||||
:anchor-align="{
|
||||
horizontal: 'center',
|
||||
vertical: 'bottom'
|
||||
}"
|
||||
:popup-align="{
|
||||
horizontal: 'center',
|
||||
vertical: 'top'
|
||||
}"
|
||||
>
|
||||
<slot/>
|
||||
</Popup>
|
||||
</template>
|
||||
<script>
|
||||
import { Popup } from '@progress/kendo-vue-popup';
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean
|
||||
},
|
||||
components: {
|
||||
Popup
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div :style="{ textAlign: 'center' }">
|
||||
<datepicker :popup="customPopup">
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom :show="props.show" />
|
||||
</template>
|
||||
</datepicker>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import './styles.css';
|
||||
|
||||
import { DatePicker } from '@progress/kendo-vue-dateinputs';
|
||||
import CustomPopup from './CustomPopup';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
datepicker: DatePicker,
|
||||
custom: CustomPopup,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
customPopup: CustomPopup,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.k-datepicker {
|
||||
width: 15em;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,16 @@
|
|||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table {
|
||||
background-color: #8bc34a;
|
||||
}
|
||||
|
||||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table thead,
|
||||
.inner-wrapper .k-calendar,
|
||||
.inner-wrapper .k-calendar table td {
|
||||
color: #ffff00;
|
||||
}
|
||||
|
||||
.inner-wrapper .k-calendar table td.k-today span.k-link,
|
||||
.inner-wrapper .k-calendar div.k-calendar-header span {
|
||||
color: #0000ff;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
[
|
||||
{
|
||||
"name": "2011",
|
||||
"data": [
|
||||
{
|
||||
"category": "Asia",
|
||||
"value": 30.8,
|
||||
"color": "#9de219",
|
||||
"labelColor": "#f00"
|
||||
},
|
||||
{
|
||||
"category": "Europe",
|
||||
"value": 21.1,
|
||||
"color": "#90cc38",
|
||||
"labelColor": "#f00"
|
||||
},
|
||||
{
|
||||
"category": "Latin America",
|
||||
"value": 16.3,
|
||||
"color": "#068c35",
|
||||
"labelColor": "#f00"
|
||||
},
|
||||
{
|
||||
"category": "Africa",
|
||||
"value": 17.6,
|
||||
"color": "#006634",
|
||||
"labelColor": "#f00"
|
||||
},
|
||||
{
|
||||
"category": "Middle East",
|
||||
"value": 9.2,
|
||||
"color": "#004d38",
|
||||
"labelColor": "#f00"
|
||||
},
|
||||
{
|
||||
"category": "North America",
|
||||
"value": 4.6,
|
||||
"color": "#033939",
|
||||
"labelColor": "#f00"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2012",
|
||||
"data": [
|
||||
{
|
||||
"category": "Asia",
|
||||
"value": 53.8,
|
||||
"color": "#9de219",
|
||||
"labelColor": "#0f0"
|
||||
},
|
||||
{
|
||||
"category": "Europe",
|
||||
"value": 16.1,
|
||||
"color": "#90cc38",
|
||||
"labelColor": "#0f0"
|
||||
},
|
||||
{
|
||||
"category": "Latin America",
|
||||
"value": 11.3,
|
||||
"color": "#068c35",
|
||||
"labelColor": "#0f0"
|
||||
},
|
||||
{
|
||||
"category": "Africa",
|
||||
"value": 9.6,
|
||||
"color": "#006634",
|
||||
"labelColor": "#0f0"
|
||||
},
|
||||
{
|
||||
"category": "Middle East",
|
||||
"value": 5.2,
|
||||
"color": "#004d38",
|
||||
"labelColor": "#0f0"
|
||||
},
|
||||
{
|
||||
"category": "North America",
|
||||
"value": 3.6,
|
||||
"color": "#033939",
|
||||
"labelColor": "#0f0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<Chart>
|
||||
<ChartTooltip :render="'renderTooltip'">
|
||||
<template v-slot:renderTooltip="{ props }">
|
||||
<div v-if="props">
|
||||
{{ props.point.category }} ({{ props.point.series.name }}):
|
||||
{{ props.point.value }}%
|
||||
</div>
|
||||
</template>
|
||||
</ChartTooltip>
|
||||
<ChartTitle :text="'Share of Internet Population Growth'" />
|
||||
<ChartLegend :visible="true" />
|
||||
<ChartArea :background="'none'" />
|
||||
<ChartSeries>
|
||||
<ChartSeriesItem
|
||||
v-for="(series, index) in internetGrowthData"
|
||||
:type="'donut'"
|
||||
:key="index"
|
||||
:startAngle="150"
|
||||
:name="series.name"
|
||||
:data-items="series.data"
|
||||
:field="'value'"
|
||||
:category-field="'category'"
|
||||
:color-field="'color'"
|
||||
:labels="seriesLabels"
|
||||
>
|
||||
</ChartSeriesItem>
|
||||
</ChartSeries>
|
||||
</Chart>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
Chart,
|
||||
ChartArea,
|
||||
ChartTitle,
|
||||
ChartTooltip,
|
||||
ChartLegend,
|
||||
ChartSeries,
|
||||
ChartSeriesItem,
|
||||
ChartSeriesLabels,
|
||||
} from '@progress/kendo-vue-charts';
|
||||
import { Group, Path, Text } from '@progress/kendo-drawing';
|
||||
|
||||
import 'hammerjs';
|
||||
|
||||
import internetGrowthData from './donut-series-data.json';
|
||||
const labelContent = function (e) {
|
||||
return `${e.category}: \n ${e.value}%`;
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Chart,
|
||||
ChartArea,
|
||||
ChartTitle,
|
||||
ChartTooltip,
|
||||
ChartLegend,
|
||||
ChartSeries,
|
||||
ChartSeriesItem,
|
||||
ChartSeriesLabels,
|
||||
},
|
||||
methods: {
|
||||
labelVisual(e) {
|
||||
const defaultLabel = e.createVisual();
|
||||
const bbox = defaultLabel.bbox();
|
||||
const group = new Group();
|
||||
|
||||
group.append(
|
||||
new Text(e.dataItem.value, [bbox.origin.x, bbox.origin.y], {
|
||||
font: `bold 15px Arial`,
|
||||
fill: {
|
||||
color: e.dataItem.labelColor,
|
||||
},
|
||||
})
|
||||
);
|
||||
return group;
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
internetGrowthData: internetGrowthData,
|
||||
labelContent: labelContent,
|
||||
seriesLabels: {
|
||||
visible: true,
|
||||
visual: this.labelVisual,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<td style="text-align: center" @mouseleave="onCellFocusOut">
|
||||
<div>
|
||||
<button
|
||||
class="k-button"
|
||||
@click="onClick"
|
||||
ref="button"
|
||||
>
|
||||
...
|
||||
</button>
|
||||
<Popup
|
||||
:anchor="'button'"
|
||||
:show="show"
|
||||
:popup-class="'popup-content'"
|
||||
@mouseleave="onFocusOut"
|
||||
@mouseenter="onMouseEnter"
|
||||
>
|
||||
<div class="action" id="accept"
|
||||
@click="onClickAction"
|
||||
>
|
||||
Mark as ready for shipping
|
||||
</div>
|
||||
<div class="action" id="decline"
|
||||
@click="onClickAction">
|
||||
Mark as not ready for shipping
|
||||
</div>
|
||||
</Popup>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import { Popup } from '@progress/kendo-vue-popup';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Popup': Popup
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
show: false,
|
||||
mouseOverPopup: false
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
this.show = false;
|
||||
},
|
||||
props: {
|
||||
dataItem: Object
|
||||
},
|
||||
methods: {
|
||||
onClick (e) {
|
||||
this.show = true;
|
||||
},
|
||||
onClickAction (e) {
|
||||
this.$emit('actionselect', {dataItem:this.dataItem, action: e.target.id});
|
||||
this.show = !this.show;
|
||||
},
|
||||
onFocusOut (e) {
|
||||
this.show = false;
|
||||
this.mouseOverPopup = false;
|
||||
},
|
||||
onCellFocusOut(e){
|
||||
setTimeout(()=>{
|
||||
if(!this.mouseOverPopup){
|
||||
this.show = false;
|
||||
}
|
||||
this.mouseOverPopup = false;
|
||||
})
|
||||
},
|
||||
onMouseEnter(){
|
||||
this.mouseOverPopup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.k-button {
|
||||
border-radius: 18px;
|
||||
background-color: grey;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.action {
|
||||
margin: 10px 20px 10px 20px;
|
||||
cursor: pointer
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,94 @@
|
|||
<template>
|
||||
<Grid ref="grid"
|
||||
:style="{height: '500px'}"
|
||||
:data-items="gridData"
|
||||
:edit-field="'inEdit'"
|
||||
:sortable="true"
|
||||
:take="take"
|
||||
:skip="skip"
|
||||
:total="total"
|
||||
:row-render="cellFunction"
|
||||
:columns="columns">
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :data-item="props.dataItem"
|
||||
@actionselect="actionSelected"
|
||||
/>
|
||||
</template>
|
||||
<grid-norecords>
|
||||
There is no data available custom
|
||||
</grid-norecords>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid, GridNoRecords } from '@progress/kendo-vue-grid';
|
||||
import ActionCell from './ActionCell';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Grid': Grid,
|
||||
'grid-norecords': GridNoRecords,
|
||||
'custom': ActionCell
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
filter: null,
|
||||
sort: null,
|
||||
gridData: [],
|
||||
skip: 0,
|
||||
take: 10,
|
||||
total: 10,
|
||||
updatedData: [],
|
||||
editID: null,
|
||||
columns: [
|
||||
{ field: 'ProductID', filterable: false, editable: false, title: 'ID', width: '80px' },
|
||||
{ field: 'ProductName', title: 'Name' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'UnitsInStock', title: 'Units', filter: 'numeric', width: '120px', editor: 'numeric' },
|
||||
{ field: 'Ready', title: 'Ready for shipping', filter: 'numeric', width: '170px', editor: 'numeric' },
|
||||
{ title: 'Change status',cell: 'myTemplate', filterable: false, width: '125px' }
|
||||
],
|
||||
gridData: []
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
this.gridData = this.createRandomData(this.total);
|
||||
},
|
||||
methods: {
|
||||
actionSelected(e){
|
||||
e.action === "accept" ? e.dataItem.Ready = true : e.dataItem.Ready = false;
|
||||
},
|
||||
createRandomData(count) {
|
||||
const productNames = ['Chai', 'Chang', 'Syrup', 'Apple', 'Orange', 'Banana', 'Lemon', 'Pineapple', 'Tea', 'Milk'];
|
||||
const unitPrices = [12.5, 10.1, 5.3, 7, 22.53, 16.22, 20, 50, 100, 120];
|
||||
const units = [2, 7, 12, 25, 67, 233, 123, 53, 67, 89];
|
||||
const trueFalse = [true, false];
|
||||
|
||||
return Array(count).fill({}).map((_, idx) => ({
|
||||
ProductID: idx + 1,
|
||||
ProductName: productNames[Math.floor(Math.random() * productNames.length)],
|
||||
UnitPrice: unitPrices[Math.floor(Math.random() * unitPrices.length)],
|
||||
UnitsInStock: units[Math.floor(Math.random() * units.length)],
|
||||
Ready: trueFalse[Math.floor(Math.random() * trueFalse.length)]
|
||||
}));
|
||||
},
|
||||
cellFunction: function (h, trElement , defaultSlots, props ) {
|
||||
const available = props.dataItem.Ready;
|
||||
const green = {
|
||||
backgroundColor: "rgb(55, 180, 0,0.32)",
|
||||
};
|
||||
const red = {
|
||||
backgroundColor: "rgb(243, 23, 0, 0.32)",
|
||||
};
|
||||
const trProps = {
|
||||
style: available ? green : red,
|
||||
};
|
||||
|
||||
return h(
|
||||
'tr',
|
||||
trProps,
|
||||
defaultSlots);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
|
@ -0,0 +1,5 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
<template>
|
||||
<grid
|
||||
:style="{ height: '280px' }"
|
||||
:data-items="items"
|
||||
:columns="columns"
|
||||
@custom="customHandler"
|
||||
>
|
||||
<template v-slot:footerTemplate1="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span> </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:footerTemplate2="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span>Custom Footer Row 1</span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span @click="customHandler">Custom Footer Row 2</span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span @click="customHandler">Column field: {{ props.field }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:footerTemplate3="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span>The sum</span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span>of the above rows is:</span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span @click="customHandler"> {{ unitPriceSum }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
grid: Grid,
|
||||
},
|
||||
computed: {
|
||||
unitPriceSum() {
|
||||
return this.items.reduce((sum, el) => (sum += el.UnitPrice), 0);
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
columns: [
|
||||
{ field: 'ProductID', footerCell: 'footerTemplate1' },
|
||||
{
|
||||
field: 'ProductName',
|
||||
title: 'Product Name',
|
||||
footerCell: 'footerTemplate2',
|
||||
},
|
||||
{
|
||||
field: 'UnitPrice',
|
||||
title: 'Unit Price',
|
||||
footerCell: 'footerTemplate3',
|
||||
},
|
||||
],
|
||||
items: [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: 'Chai',
|
||||
UnitPrice: 1,
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: 'Chang',
|
||||
UnitPrice: 2.2,
|
||||
},
|
||||
{
|
||||
ProductID: 3,
|
||||
ProductName: 'Aniseed Syrup',
|
||||
UnitPrice: 3.0,
|
||||
},
|
||||
{
|
||||
ProductID: 4,
|
||||
ProductName: "Chef Anton's Cajun Seasoning",
|
||||
UnitPrice: 4.0,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
customHandler: function (e) {
|
||||
console.log('customHandler', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
div.k-grid-footer > div > table > tfoot > tr > td {
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
tfoot > tr > td:nth-child(3) {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.first-footer-row,
|
||||
.second-footer-row {
|
||||
border-bottom: 1px solid green;
|
||||
border-color: rgba(0, 0, 0, 0.08);
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<td v-if="renderCell" :class="className">
|
||||
<b v-if="field !== 'selected'">{{ getNestedValue(field, dataItem) }}</b>
|
||||
<span v-else>
|
||||
<kcheckbox
|
||||
:checked="getNestedValue(field, dataItem)"
|
||||
id="inputId"
|
||||
@change="handleOnChange"
|
||||
/>
|
||||
<label class="k-checkbox-label" for="inputId" />
|
||||
</span>
|
||||
</td>
|
||||
<td v-else-if="renderArrow" key="'g' + columnIndex" :class="'k-group-cell'"></td>
|
||||
|
||||
<td v-else-if="columnIndex <= level" key="g-colspan" :colSpan="columnsCount - columnIndex">
|
||||
<p class="k-reset">
|
||||
<a
|
||||
@click="onClick"
|
||||
tabindex="-1"
|
||||
href="#"
|
||||
:class="expanded ? 'k-i-collapse k-icon' : 'k-i-expand k-icon'"
|
||||
/>
|
||||
{{ dataItem[field] }}
|
||||
</p>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
import { guid } from '@progress/kendo-vue-common';
|
||||
import { Checkbox } from '@progress/kendo-vue-inputs';
|
||||
|
||||
function nestedValue(fieldName, dataItem) {
|
||||
const path = fieldName.split('.');
|
||||
let data = dataItem;
|
||||
path.forEach((p) => {
|
||||
data = data ? data[p] : undefined;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
kcheckbox: Checkbox,
|
||||
},
|
||||
emits: {
|
||||
click: null,
|
||||
selectionchange: null,
|
||||
},
|
||||
props: {
|
||||
isSelected: Boolean,
|
||||
field: String,
|
||||
dataItem: Object,
|
||||
format: String,
|
||||
className: String,
|
||||
columnIndex: Number,
|
||||
columnsCount: Number,
|
||||
rowType: String,
|
||||
level: Number,
|
||||
expanded: Boolean,
|
||||
editor: String,
|
||||
},
|
||||
created() {
|
||||
this.inputId = guid();
|
||||
},
|
||||
computed: {
|
||||
renderArrow() {
|
||||
var returnValue =
|
||||
this.columnIndex === undefined ||
|
||||
this.level === undefined ||
|
||||
this.columnIndex < this.level ||
|
||||
this.columnsCount === undefined ||
|
||||
this.rowType !== 'groupHeader' ||
|
||||
this.dataItem[this.field] === undefined;
|
||||
return returnValue && this.dataItem[this.field];
|
||||
},
|
||||
renderCell() {
|
||||
return this.field !== undefined && this.rowType !== 'groupHeader';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleOnChange(event) {
|
||||
this.$emit('selectionchange', {
|
||||
event: event,
|
||||
dataItem: this.$props.dataItem,
|
||||
});
|
||||
},
|
||||
onClick(e) {
|
||||
this.$emit('click', e, this.dataItem, this.expanded);
|
||||
},
|
||||
getNestedValue: nestedValue,
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<Grid ref="grid"
|
||||
:selected-field="selectedField"
|
||||
:cell-render="cellTemplate"
|
||||
:style="{height: '520px'}"
|
||||
:data-items="gridData"
|
||||
:resizable="true"
|
||||
:reorderable="true"
|
||||
:sortable="true"
|
||||
:pageable="gridPageable"
|
||||
:groupable="true"
|
||||
:group= "group"
|
||||
:take="take"
|
||||
:skip="skip"
|
||||
:expand-field="'expanded'"
|
||||
:columns="columns"
|
||||
@headerselectionchange="onHeaderSelectionChange"
|
||||
@rowclick="onRowClick"
|
||||
@datastatechange="dataStateChange"
|
||||
@expandchange="expandChange">
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :field="props.field"
|
||||
:expanded="props.expanded"
|
||||
:row-type="props.rowType"
|
||||
:level="props.level"
|
||||
:column-index="props.columnIndex"
|
||||
:columns-count="props.columnsCount"
|
||||
:data-item="props.dataItem"
|
||||
:class-name="props.className"
|
||||
@selectionchange="selectionChange"
|
||||
@click="clickHandler(props.dataItem)" />
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { process } from '@progress/kendo-data-query';
|
||||
import CustomCell from './CustomCell';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Grid': Grid,
|
||||
'custom': CustomCell
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
selectedField: 'selected',
|
||||
cellTemplate: 'myTemplate',
|
||||
gridPageable: { pageSizes: true },
|
||||
products: this.createRandomData(1000),
|
||||
gridData: [],
|
||||
skip: 0,
|
||||
take: 10,
|
||||
group: [ { field: 'UnitsInStock' } ],
|
||||
expandedItems: [],
|
||||
staticColumns: [
|
||||
{ field: 'ProductID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'UnitsInStock', title: 'Units In Stock' }
|
||||
]
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
this.getData();
|
||||
},
|
||||
computed: {
|
||||
areAllSelected () {
|
||||
return this.products.findIndex(item => item.selected === false) === -1;
|
||||
},
|
||||
columns () {
|
||||
return [
|
||||
...this.staticColumns,
|
||||
{ field: 'selected', width: '50px', headerSelectionValue: this.areAllSelected },
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onHeaderSelectionChange (event) {
|
||||
let checked = event.event.target.checked;
|
||||
this.products = this.products.map((item) => { return {...item, selected: checked} });
|
||||
this.getData();
|
||||
},
|
||||
selectionChange (event) {
|
||||
event.dataItem[this.selectedField] = !event.dataItem[this.selectedField];
|
||||
},
|
||||
onRowClick (event) {
|
||||
event.dataItem[this.selectedField] = !event.dataItem[this.selectedField];
|
||||
},
|
||||
clickHandler(dataItem){
|
||||
if(dataItem){
|
||||
dataItem.expanded = dataItem.expanded === undefined ? false : !dataItem.expanded;
|
||||
}
|
||||
|
||||
},
|
||||
getData: function () {
|
||||
this.gridData = process(this.products, {take: this.take, skip: this.skip, group: this.group});
|
||||
},
|
||||
createAppState: function(dataState) {
|
||||
this.group = dataState.group;
|
||||
this.take = dataState.take;
|
||||
this.skip = dataState.skip;
|
||||
this.getData();
|
||||
},
|
||||
dataStateChange: function (event) {
|
||||
this.createAppState(event.data);
|
||||
},
|
||||
expandChange: function (event) {
|
||||
if (event.dataItem) {
|
||||
event.dataItem[event.target.$props.expandField] = event.value;
|
||||
}
|
||||
},
|
||||
createRandomData(count) {
|
||||
const productNames = ['Chai', 'Chang', 'Syrup', 'Apple', 'Orange', 'Banana', 'Lemon', 'Pineapple', 'Tea', 'Milk'];
|
||||
const unitPrices = [12.5, 10.1, 5.3, 7, 22.53, 16.22, 20, 50, 100, 120];
|
||||
const units = [2, 7, 12, 25, 67, 233, 123, 53, 67, 89];
|
||||
|
||||
return Array(count).fill({}).map((_, idx) => ({
|
||||
ProductID: idx + 1,
|
||||
ProductName: productNames[Math.floor(Math.random() * productNames.length)],
|
||||
UnitPrice: unitPrices[Math.floor(Math.random() * unitPrices.length)],
|
||||
UnitsInStock: units[Math.floor(Math.random() * units.length)],
|
||||
selected: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<Grid :style="{ height: '200px' }" :data-items="products" :columns="columns">
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from "@progress/kendo-vue-grid";
|
||||
const products = [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: "Chai",
|
||||
SupplierID: 1,
|
||||
CategoryID: 1,
|
||||
QuantityPerUnit: "10 boxes x 20 bags",
|
||||
UnitPrice: "18",
|
||||
UnitsInStock: 39,
|
||||
UnitsOnOrder: 0,
|
||||
ReorderLevel: 10,
|
||||
Discontinued: false,
|
||||
Category: {
|
||||
CategoryID: 1,
|
||||
CategoryName: "Beverages",
|
||||
Description: "Soft drinks, coffees, teas, beers, and ales"
|
||||
},
|
||||
FirstOrderedOn: "1996-09-19T23:00:00.000Z"
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: "Chang",
|
||||
SupplierID: 1,
|
||||
CategoryID: 1,
|
||||
QuantityPerUnit: "24 - 12 oz bottles",
|
||||
UnitPrice: "21.3545677",
|
||||
UnitsInStock: 17,
|
||||
UnitsOnOrder: 40,
|
||||
ReorderLevel: 25,
|
||||
Discontinued: false,
|
||||
Category: {
|
||||
CategoryID: 1,
|
||||
CategoryName: "Beverages",
|
||||
Description: "Soft drinks, coffees, teas, beers, and ales"
|
||||
},
|
||||
FirstOrderedOn: "1996-08-11T23:00:00.000Z"
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
products: products,
|
||||
columns: [
|
||||
{
|
||||
field: "ProductID",
|
||||
title: "Product ID",
|
||||
width: "50px"
|
||||
},
|
||||
{ field: "ProductName", title: "Product Name" },
|
||||
{
|
||||
field: "FirstOrderedOn",
|
||||
title: "Formatted ISO Date",
|
||||
type: "date",
|
||||
format: "{0:yyyy-MM-ddTHH:mm:ssXXX}"
|
||||
},
|
||||
{
|
||||
field: "UnitPrice",
|
||||
title: "Formatted Unit Price",
|
||||
type: "number",
|
||||
format: "{0:c}"
|
||||
},
|
||||
{ field: "Discontinued", filter: "boolean", title: "Discontinued" }
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<td v-if="renderCell && field!=='expanded'" :class="className">
|
||||
<b>{{ getNestedValue(field, dataItem)}}</b></td>
|
||||
<td v-else-if="renderCell" :class="'k-hierarchy-cell'">
|
||||
<span :class="customClass" @click="onDetailClick"/></td>
|
||||
<td v-else-if="renderArrow" key="'g' + columnIndex" :class="'k-group-cell'" >
|
||||
</td>
|
||||
<td v-else-if="columnIndex <= level" key='g-colspan'
|
||||
:colSpan="columnsCount - columnIndex">
|
||||
<p class="k-reset">
|
||||
<span
|
||||
@click="onClick"
|
||||
tabIndex="-1"
|
||||
:class="expanded ? 'k-i-collapse k-icon' : 'k-i-expand k-icon'"
|
||||
/>
|
||||
{{dataItem[field]}}
|
||||
</p>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
|
||||
function nestedValue(fieldName, dataItem) {
|
||||
const path = fieldName.split('.');
|
||||
let data = dataItem;
|
||||
path.forEach((p) => {
|
||||
data = data ? data[p] : undefined;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export default {
|
||||
emits:{
|
||||
click: null
|
||||
},
|
||||
props: {
|
||||
detail: String,
|
||||
field: String,
|
||||
dataItem: Object,
|
||||
format: String,
|
||||
className: String,
|
||||
columnIndex: Number,
|
||||
columnsCount: Number,
|
||||
rowType: String,
|
||||
level: Number,
|
||||
expanded: Boolean,
|
||||
editor: String,
|
||||
},
|
||||
computed: {
|
||||
renderArrow(){
|
||||
var returnValue = this.columnIndex === undefined ||this.level === undefined ||
|
||||
this.columnIndex < this.level ||this.columnsCount === undefined ||
|
||||
this.rowType !== 'groupHeader' || this.dataItem[this.field] === undefined;
|
||||
return returnValue && this.dataItem[this.field];
|
||||
},
|
||||
renderCell(){
|
||||
return this.field !== undefined && this.rowType !== 'groupHeader';
|
||||
},
|
||||
customClass(){
|
||||
const expanded = this.getNestedValue(this.$props.field, this.$props.dataItem);
|
||||
const className = expanded ? 'k-icon k-i-minus' : 'k-icon k-i-plus';
|
||||
return className;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick(e) {
|
||||
this.$emit('click', e, this.dataItem, this.expanded);
|
||||
},
|
||||
onDetailClick(e){
|
||||
const expanded = this.getNestedValue(this.$props.field, this.$props.dataItem);
|
||||
|
||||
this.$emit('click', e, this.dataItem, expanded);
|
||||
},
|
||||
getNestedValue: nestedValue
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<Grid ref="grid"
|
||||
:cell-render="cellTemplate"
|
||||
:style="{height: '520px'}"
|
||||
:data-items="gridData"
|
||||
:resizable="true"
|
||||
:reorderable="true"
|
||||
:sortable="true"
|
||||
:pageable="gridPageable"
|
||||
:groupable="true"
|
||||
:group= "group"
|
||||
:take="take"
|
||||
:skip="skip"
|
||||
:expand-field="'expanded'"
|
||||
:detail="cellDetailTemplate"
|
||||
:columns="columns"
|
||||
@datastatechange="dataStateChange"
|
||||
@expandchange="expandChange">
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :field="props.field"
|
||||
:expanded="props.expanded"
|
||||
:row-type="props.rowType"
|
||||
:level="props.level"
|
||||
:column-index="props.columnIndex"
|
||||
:columns-count="props.columnsCount"
|
||||
:data-item="props.dataItem"
|
||||
:class-name="props.className"
|
||||
@click="clickHandler(props.dataItem)" />
|
||||
</template>
|
||||
<template v-slot:cellDetailTemplate="{props}">
|
||||
<section>
|
||||
<p><strong>Descriptions:</strong> {{props.dataItem.ProductName}}</p>
|
||||
</section>
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { process } from '@progress/kendo-data-query';
|
||||
import CustomCell from './CustomCell';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Grid': Grid,
|
||||
'custom': CustomCell
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
cellDetailTemplate: 'cellDetailTemplate',
|
||||
cellTemplate: 'myTemplate',
|
||||
gridPageable: { pageSizes: true },
|
||||
products: this.createRandomData(1000),
|
||||
gridData: [],
|
||||
skip: 0,
|
||||
take: 10,
|
||||
group: [ { field: 'UnitsInStock' } ],
|
||||
expandedItems: [],
|
||||
columns: [
|
||||
{ field: 'ProductID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'UnitsInStock', title: 'Units In Stock' }
|
||||
]
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
this.getData();
|
||||
},
|
||||
methods: {
|
||||
clickHandler(dataItem){
|
||||
dataItem.expanded = dataItem.expanded === undefined ? true : !dataItem.expanded;
|
||||
},
|
||||
getData: function () {
|
||||
this.gridData = process(this.products, {take: this.take, skip: this.skip, group: this.group});
|
||||
},
|
||||
createAppState: function(dataState) {
|
||||
this.group = dataState.group;
|
||||
this.take = dataState.take;
|
||||
this.skip = dataState.skip;
|
||||
this.getData();
|
||||
},
|
||||
dataStateChange: function (event) {
|
||||
this.createAppState(event.data);
|
||||
},
|
||||
expandChange: function (event) {
|
||||
debugger
|
||||
event.dataItem[event.target.$props.expandField] = event.value;
|
||||
},
|
||||
createRandomData(count) {
|
||||
const productNames = ['Chai', 'Chang', 'Syrup', 'Apple', 'Orange', 'Banana', 'Lemon', 'Pineapple', 'Tea', 'Milk'];
|
||||
const unitPrices = [12.5, 10.1, 5.3, 7, 22.53, 16.22, 20, 50, 100, 120];
|
||||
const units = [2, 7, 12, 25, 67, 233, 123, 53, 67, 89];
|
||||
|
||||
return Array(count).fill({}).map((_, idx) => ({
|
||||
ProductID: idx + 1,
|
||||
ProductName: productNames[Math.floor(Math.random() * productNames.length)],
|
||||
UnitPrice: unitPrices[Math.floor(Math.random() * unitPrices.length)],
|
||||
UnitsInStock: units[Math.floor(Math.random() * units.length)]
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<td v-if="!dataItem['inEdit']">
|
||||
<kbutton
|
||||
:theme-color="'primary'"
|
||||
class="k-grid-edit-command"
|
||||
@click="editHandler">
|
||||
Edit
|
||||
</kbutton>
|
||||
<kbutton
|
||||
class="k-grid-remove-command"
|
||||
@click="removeHandler">
|
||||
Remove
|
||||
</kbutton>
|
||||
</td>
|
||||
<td v-else>
|
||||
<kbutton
|
||||
class="k-grid-save-command"
|
||||
@click="addUpdateHandler">
|
||||
{{dataItem.ProductID? 'Update' : 'Add'}}
|
||||
</kbutton>
|
||||
<kbutton
|
||||
class="k-grid-cancel-command"
|
||||
@click="cancelDiscardHandler">
|
||||
{{dataItem.ProductID? 'Cancel' : 'Discard'}}
|
||||
</kbutton>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
export default {
|
||||
components: {
|
||||
'kbutton': Button
|
||||
},
|
||||
props: {
|
||||
field: String,
|
||||
dataItem: Object,
|
||||
format: String,
|
||||
className: String,
|
||||
columnIndex: Number,
|
||||
columnsCount: Number,
|
||||
rowType: String,
|
||||
level: Number,
|
||||
expanded: Boolean,
|
||||
editor: String
|
||||
},
|
||||
methods: {
|
||||
editHandler: function() {
|
||||
this.$emit('edit', {dataItem:this.dataItem});
|
||||
},
|
||||
removeHandler: function() {
|
||||
this.$emit('remove', {dataItem:this.dataItem});
|
||||
},
|
||||
addUpdateHandler: function() {
|
||||
this.$emit('save', {dataItem:this.dataItem});
|
||||
},
|
||||
cancelDiscardHandler: function() {
|
||||
this.$emit('cancel', {dataItem:this.dataItem});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<td v-if="!dataItem.inEdit" :class="className">
|
||||
<div class="status-cell">
|
||||
Status:
|
||||
{{ dataItem[field].active }}
|
||||
</div>
|
||||
<div class="status-cell">
|
||||
Public:
|
||||
{{ dataItem[field].public }}
|
||||
</div>
|
||||
<div class="status-cell">
|
||||
Hide:
|
||||
{{ dataItem[field].hide }}
|
||||
</div>
|
||||
</td>
|
||||
<td :class="className" v-else>
|
||||
<div class="status-cell">
|
||||
Status:
|
||||
<kcheckbox :checked="dataItem[field].active" @change="activeChange" />
|
||||
</div>
|
||||
<div class="status-cell">
|
||||
Public:
|
||||
<kcheckbox :checked="dataItem[field].public" @change="publicChange" />
|
||||
</div>
|
||||
<div class="status-cell">
|
||||
Hide:
|
||||
<kcheckbox :checked="dataItem[field].hide" @change="hideChange" />
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
import { Checkbox } from '@progress/kendo-vue-inputs';
|
||||
export default {
|
||||
components: {
|
||||
kcheckbox: Checkbox,
|
||||
},
|
||||
props: {
|
||||
field: String,
|
||||
dataItem: Object,
|
||||
format: String,
|
||||
className: String,
|
||||
columnIndex: Number,
|
||||
columnsCount: Number,
|
||||
rowType: String,
|
||||
level: Number,
|
||||
expanded: Boolean,
|
||||
editor: String,
|
||||
},
|
||||
methods: {
|
||||
activeChange(e) {
|
||||
this.$emit('activeChange', e, e.value);
|
||||
},
|
||||
publicChange(e) {
|
||||
this.$emit('publicChange', e, e.value);
|
||||
},
|
||||
hideChange(e) {
|
||||
this.$emit('hideChange', e, e.value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.status-cell {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,255 @@
|
|||
<template>
|
||||
<Grid
|
||||
ref="grid"
|
||||
:style="{ height: '440px' }"
|
||||
:data-items="gridData"
|
||||
:edit-field="'inEdit'"
|
||||
@itemchange="itemChange"
|
||||
:columns="columns"
|
||||
>
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom
|
||||
:data-item="props.dataItem"
|
||||
@edit="edit"
|
||||
@save="save"
|
||||
@remove="remove"
|
||||
@cancel="cancel"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:statusCell="{ props }">
|
||||
<statusCell
|
||||
:data-item="props.dataItem"
|
||||
:field="props.field"
|
||||
:class-name="'statusColumn'"
|
||||
@activeChange="(e) => activeChange(e, props.dataItem)"
|
||||
@publicChange="(e) => publicChange(e, props.dataItem)"
|
||||
@hideChange="(e) => hideChange(e, props.dataItem)"
|
||||
/>
|
||||
</template>
|
||||
<grid-toolbar>
|
||||
<kbutton title="Add new" :theme-color="'primary'" @click="insert">
|
||||
Add new
|
||||
</kbutton>
|
||||
<kbutton
|
||||
v-if="hasItemsInEdit"
|
||||
title="Cancel current changes"
|
||||
@click="cancelChanges"
|
||||
>
|
||||
Cancel current changes
|
||||
</kbutton>
|
||||
</grid-toolbar>
|
||||
<grid-norecords> There is no data available custom </grid-norecords>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid, GridToolbar, GridNoRecords } from '@progress/kendo-vue-grid';
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
import CommandCell from './CommandCell';
|
||||
import StatusCell from './StatusCell';
|
||||
|
||||
var sampleProducts = [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: 'Chai',
|
||||
UnitsInStock: 39,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 20),
|
||||
Status: {
|
||||
active: true,
|
||||
public: false,
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: 'Chang',
|
||||
UnitsInStock: 17,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 7, 12),
|
||||
Status: {
|
||||
active: true,
|
||||
public: false,
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ProductID: 3,
|
||||
ProductName: 'Aniseed Syrup',
|
||||
UnitsInStock: 13,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 26),
|
||||
Status: {
|
||||
active: true,
|
||||
public: false,
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ProductID: 4,
|
||||
ProductName: "Chef Anton's Cajun Seasoning",
|
||||
UnitsInStock: 53,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
Status: {
|
||||
active: true,
|
||||
public: false,
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
'grid-toolbar': GridToolbar,
|
||||
'grid-norecords': GridNoRecords,
|
||||
custom: CommandCell,
|
||||
statusCell: StatusCell,
|
||||
kbutton: Button,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
gridData: sampleProducts.slice(0),
|
||||
updatedData: [],
|
||||
editID: null,
|
||||
group: [{ field: 'UnitsInStock' }],
|
||||
expandedItems: [],
|
||||
columns: [
|
||||
{ field: 'ProductID', editable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'ProductName', title: 'Name' },
|
||||
{
|
||||
field: 'FirstOrderedOn',
|
||||
editor: 'date',
|
||||
title: 'First Ordered',
|
||||
format: '{0:d}',
|
||||
},
|
||||
{
|
||||
field: 'UnitsInStock',
|
||||
title: 'Units',
|
||||
width: '70px',
|
||||
editor: 'numeric',
|
||||
},
|
||||
{
|
||||
field: 'Status',
|
||||
title: 'Status',
|
||||
cell: 'statusCell',
|
||||
width: '120px',
|
||||
},
|
||||
{ cell: 'myTemplate', width: '180px' },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasItemsInEdit() {
|
||||
return this.gridData.filter((p) => p.inEdit).length > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
activeChange: function (e, dataItem) {
|
||||
const updatedData = this.gridData.slice();
|
||||
|
||||
const item = this.update(updatedData, dataItem);
|
||||
item.Status.active = e.value;
|
||||
this.gridData = updatedData;
|
||||
},
|
||||
publicChange: function (e, dataItem) {
|
||||
const updatedData = this.gridData.slice();
|
||||
|
||||
const item = this.update(updatedData, dataItem);
|
||||
item.Status.public = e.value;
|
||||
this.gridData = updatedData;
|
||||
},
|
||||
hideChange: function (e, dataItem) {
|
||||
const updatedData = this.gridData.slice();
|
||||
|
||||
const item = this.update(updatedData, dataItem);
|
||||
item.Status.hide = e.value;
|
||||
this.gridData = updatedData;
|
||||
},
|
||||
ddChange: function (e, dataItem) {
|
||||
const updatedData = this.gridData.slice();
|
||||
|
||||
const item = this.update(updatedData, dataItem);
|
||||
item.Discontinued = e.target.value;
|
||||
this.gridData = updatedData;
|
||||
},
|
||||
itemChange: function (e) {
|
||||
const updatedData = this.gridData.slice();
|
||||
|
||||
const item = this.update(updatedData, e.dataItem);
|
||||
item[e.field] = e.value;
|
||||
this.gridData = updatedData;
|
||||
},
|
||||
insert() {
|
||||
const dataItem = { inEdit: true, Discontinued: false };
|
||||
const newproducts = this.gridData.slice();
|
||||
newproducts.unshift(dataItem);
|
||||
this.update(newproducts, dataItem);
|
||||
this.gridData = newproducts;
|
||||
},
|
||||
edit: function (e) {
|
||||
e.dataItem.inEdit = true;
|
||||
},
|
||||
save: function (e) {
|
||||
e.dataItem.inEdit = undefined;
|
||||
const data = this.gridData.slice();
|
||||
e.dataItem.ProductID = this.update(sampleProducts, e.dataItem).ProductID;
|
||||
},
|
||||
update(data, item, remove) {
|
||||
let updated;
|
||||
let itemProductID = item.ProductID;
|
||||
let index = data.findIndex(
|
||||
(p) =>
|
||||
JSON.stringify({ ...p }) === JSON.stringify(item) ||
|
||||
(itemProductID && p.ProductID === itemProductID)
|
||||
);
|
||||
if (index >= 0) {
|
||||
updated = Object.assign({}, item);
|
||||
data[index] = updated;
|
||||
} else {
|
||||
let id = 1;
|
||||
data.forEach((p) => {
|
||||
id = Math.max(p.ProductID + 1, id);
|
||||
});
|
||||
updated = Object.assign({}, item, { ProductID: id });
|
||||
data.unshift(updated);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
data = data.splice(index, 1);
|
||||
}
|
||||
return data[index];
|
||||
},
|
||||
cancel(e) {
|
||||
if (e.dataItem.ProductID) {
|
||||
e.dataItem.inEdit = undefined;
|
||||
} else {
|
||||
this.update(this.gridData, e.dataItem, true);
|
||||
}
|
||||
},
|
||||
remove(e) {
|
||||
e.dataItem.inEdit = undefined;
|
||||
this.update(this.gridData, e.dataItem, true);
|
||||
this.update(sampleProducts, e.dataItem, true);
|
||||
this.gridData = this.gridData.slice();
|
||||
},
|
||||
cancelChanges() {
|
||||
let editedItems = sampleProducts.filter((p) => p.inEdit === true);
|
||||
if (editedItems.length) {
|
||||
editedItems.forEach((item) => {
|
||||
item.inEdit = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
this.gridData = sampleProducts.slice();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.k-grid td.statusColumn {
|
||||
padding: 0px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<td @dragover="dragOver">
|
||||
<span class="k-icon k-i-reorder"
|
||||
draggable="true"
|
||||
style="cursor: 'move'"
|
||||
@dragstart="dragStart"
|
||||
@dragend="dragEnd">
|
||||
</span>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
emits:{
|
||||
dragover: null,
|
||||
dragstart: null,
|
||||
dragend: null
|
||||
},
|
||||
props: {
|
||||
dataItem: Object
|
||||
},
|
||||
methods: {
|
||||
dragOver(e){
|
||||
this.$emit('dragover', this.dataItem);
|
||||
},
|
||||
dragStart(e) {
|
||||
this.$emit('dragstart', this.dataItem);
|
||||
},
|
||||
dragEnd(e) {
|
||||
this.$emit('dragend');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,160 @@
|
|||
<template>
|
||||
<Grid :data-items="items" :columns="columns">
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom
|
||||
:data-item="props.dataItem"
|
||||
@dragover="reorder"
|
||||
@dragstart="setActive"
|
||||
@dragend="updateRemote"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Grid :data-items="items2" :columns="columns">
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom
|
||||
:data-item="props.dataItem"
|
||||
@dragover="reorder2"
|
||||
@dragstart="setActive"
|
||||
@dragend="updateRemote"
|
||||
/>
|
||||
</template>
|
||||
<grid-norecords @dragover="addRecordToEmptyGrid">
|
||||
<div>Drop the item here</div>
|
||||
</grid-norecords>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid, GridNoRecords } from '@progress/kendo-vue-grid';
|
||||
import CustomCell from './CustomCell';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
custom: CustomCell,
|
||||
'grid-norecords': GridNoRecords,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
items: [],
|
||||
items2: [],
|
||||
columns: [
|
||||
{
|
||||
field: 'Drag',
|
||||
title: '',
|
||||
cell: 'myTemplate',
|
||||
width: '80px',
|
||||
title: 'Reorder',
|
||||
},
|
||||
{ field: 'ProductID' },
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'UnitPrice', title: 'Unit Price' },
|
||||
],
|
||||
activeItem: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
createRandomData(count) {
|
||||
const productNames = [
|
||||
'Chai',
|
||||
'Chang',
|
||||
'Syrup',
|
||||
'Apple',
|
||||
'Orange',
|
||||
'Banana',
|
||||
'Lemon',
|
||||
'Pineapple',
|
||||
'Tea',
|
||||
'Milk',
|
||||
];
|
||||
const unitPrices = [12.5, 10.1, 5.3, 7, 22.53, 16.22, 20, 50, 100, 120];
|
||||
|
||||
return Array(count)
|
||||
.fill({})
|
||||
.map((_, idx) => ({
|
||||
ProductID: idx + 1,
|
||||
ProductName:
|
||||
productNames[Math.floor(Math.random() * productNames.length)],
|
||||
UnitPrice: unitPrices[Math.floor(Math.random() * unitPrices.length)],
|
||||
}));
|
||||
},
|
||||
reorder(dataItem) {
|
||||
let that = this;
|
||||
|
||||
if (that.activeItem === dataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
let reorderedData = this.items.slice();
|
||||
let reorderedDataItemsArr = this.items2.slice();
|
||||
let prevIndex = reorderedData.findIndex((p) => p === that.activeItem);
|
||||
let nextIndex = reorderedData.findIndex((p) => p === dataItem);
|
||||
|
||||
if (prevIndex !== -1) {
|
||||
reorderedData.splice(prevIndex, 1);
|
||||
reorderedData.splice(nextIndex, 0, this.activeItem);
|
||||
} else {
|
||||
reorderedData.push(this.activeItem);
|
||||
const itemsArrAcriveElementIndex = reorderedDataItemsArr.findIndex(
|
||||
(p) => p === that.activeItem
|
||||
);
|
||||
reorderedDataItemsArr.splice(itemsArrAcriveElementIndex, 1);
|
||||
}
|
||||
that.items = reorderedData;
|
||||
that.items2 = reorderedDataItemsArr;
|
||||
},
|
||||
reorder2(dataItem) {
|
||||
let that = this;
|
||||
|
||||
if (that.activeItem === dataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
let reorderedData = this.items2.slice();
|
||||
let reorderedDataItemsArr = this.items.slice();
|
||||
let prevIndex = reorderedData.findIndex((p) => p === that.activeItem);
|
||||
let nextIndex = reorderedData.findIndex((p) => p === dataItem);
|
||||
|
||||
if (prevIndex !== -1) {
|
||||
reorderedData.splice(prevIndex, 1);
|
||||
reorderedData.splice(nextIndex, 0, this.activeItem);
|
||||
} else {
|
||||
reorderedData.push(this.activeItem);
|
||||
const itemsArrAcriveElementIndex = reorderedDataItemsArr.findIndex(
|
||||
(p) => p === that.activeItem
|
||||
);
|
||||
reorderedDataItemsArr.splice(itemsArrAcriveElementIndex, 1);
|
||||
}
|
||||
that.items2 = reorderedData;
|
||||
that.items = reorderedDataItemsArr;
|
||||
},
|
||||
setActive(dataItem) {
|
||||
this.activeItem = dataItem;
|
||||
},
|
||||
updateRemote() {
|
||||
console.log(
|
||||
'Drag end. Send request to remote to update the source order'
|
||||
);
|
||||
|
||||
// Send request to remote to update the source order
|
||||
},
|
||||
addRecordToEmptyGrid: function (dataItem) {
|
||||
const that = this;
|
||||
this.items2.push(this.activeItem);
|
||||
|
||||
let reorderedDataItemsArr = this.items.slice();
|
||||
const itemsArrAcriveElementIndex = reorderedDataItemsArr.findIndex(
|
||||
(p) => p === that.activeItem
|
||||
);
|
||||
reorderedDataItemsArr.splice(itemsArrAcriveElementIndex, 1);
|
||||
this.items = reorderedDataItemsArr;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.items = this.createRandomData(10);
|
||||
this.items2 = [];
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,5 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<grid :style="{ height: '280px' }" :data-items="items" :columns="columns">
|
||||
<template v-slot:headerTemplate="{ props }">
|
||||
<span
|
||||
v-if="!getColumnItem(props).headerInEdit"
|
||||
@dblclick="(e) => customHandler(e, props)"
|
||||
>{{ props.title }}</span
|
||||
>
|
||||
<span v-else
|
||||
><k-input
|
||||
@blur="onBlur(props)"
|
||||
@input="(e) => onInput(e, props)"
|
||||
type="text"
|
||||
:value="props.title"
|
||||
/></span>
|
||||
</template>
|
||||
</grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { Input } from '@progress/kendo-vue-inputs';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
grid: Grid,
|
||||
'k-input': Input,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
unitPriceTitle: 'Unit price',
|
||||
columns: [
|
||||
{
|
||||
field: 'ProductID',
|
||||
title: 'Product ID',
|
||||
headerCell: 'headerTemplate',
|
||||
headerInEdit: false,
|
||||
},
|
||||
{
|
||||
field: 'ProductName',
|
||||
title: 'Product Name',
|
||||
headerCell: 'headerTemplate',
|
||||
headerInEdit: false,
|
||||
},
|
||||
{
|
||||
field: 'UnitPrice',
|
||||
title: 'Unit Price',
|
||||
headerCell: 'headerTemplate',
|
||||
headerInEdit: false,
|
||||
},
|
||||
],
|
||||
items: [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: 'Chai',
|
||||
UnitPrice: 18.0,
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: 'Chang',
|
||||
UnitPrice: 19.0,
|
||||
},
|
||||
{
|
||||
ProductID: 3,
|
||||
ProductName: 'Aniseed Syrup',
|
||||
UnitPrice: 10.0,
|
||||
},
|
||||
{
|
||||
ProductID: 4,
|
||||
ProductName: "Chef Anton's Cajun Seasoning",
|
||||
UnitPrice: 22.0,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
customHandler: function (e, props) {
|
||||
const item = this.getColumnItem(props);
|
||||
item.headerInEdit = true;
|
||||
},
|
||||
onBlur: function (props) {
|
||||
const item = this.getColumnItem(props);
|
||||
item.headerInEdit = false;
|
||||
},
|
||||
onInput: function (e, props) {
|
||||
const item = this.getColumnItem(props);
|
||||
item.title = e.value;
|
||||
},
|
||||
getColumnItem(props) {
|
||||
return this.columns.find((el) => el.title === props.title);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<grid :data-items="getFilteredProducts"
|
||||
:columns="columns">
|
||||
</grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { filterBy } from '@progress/kendo-data-query';
|
||||
import { products } from './products';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
grid: Grid
|
||||
},
|
||||
props: {
|
||||
dataItem: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
products: products,
|
||||
columns: [
|
||||
{ field: 'ProductID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'UnitsInStock', title: 'Units In Stock' },
|
||||
{ field: 'Category.CategoryName', title: 'Category Name' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getFilteredProducts() {
|
||||
const result = filterBy(this.products, {field: 'Category.CategoryID', operator: 'eq', value: this.dataItem.CategoryID});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<Grid
|
||||
ref="grid"
|
||||
:style="{ height: '550px' }"
|
||||
:columns="columns"
|
||||
:data-items="categories"
|
||||
:detail="cellTemplate"
|
||||
@expandchange="expandChange"
|
||||
:expand-field="'expanded'"
|
||||
>
|
||||
<grid-toolbar>
|
||||
<KButton
|
||||
class="k-button k-primary"
|
||||
:title="'Export PDF'"
|
||||
@click="exportExcel"
|
||||
>
|
||||
Export to Excel
|
||||
</KButton>
|
||||
</grid-toolbar>
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom :data-item="props.dataItem" />
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
import { Grid, GridToolbar } from '@progress/kendo-vue-grid';
|
||||
import { products } from './products';
|
||||
import DetailComponent from './DetailComponent';
|
||||
import { workbookOptions, toDataURL } from '@progress/kendo-vue-excel-export';
|
||||
import { saveAs } from '@progress/kendo-file-saver';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
KButton: Button,
|
||||
custom: DetailComponent,
|
||||
'grid-toolbar': GridToolbar,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
cellTemplate: 'myTemplate',
|
||||
products: products,
|
||||
expandedItems: [],
|
||||
columns: [
|
||||
{ field: 'CategoryID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'CategoryName', title: 'Category Name' },
|
||||
{ field: 'Descriptions', title: 'Descriptions' },
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
CategoryID: 1,
|
||||
CategoryName: 'Beverages',
|
||||
Descriptions: 'Soft drinks, coffees, teas, beers, and ales',
|
||||
},
|
||||
{
|
||||
CategoryID: 2,
|
||||
CategoryName: 'Condiments',
|
||||
Descriptions:
|
||||
'Sweet and savory sauces, relishes, spreads, and seasonings',
|
||||
},
|
||||
{
|
||||
CategoryID: 3,
|
||||
CategoryName: 'Confections',
|
||||
Descriptions: 'Desserts, candies, and sweet breads',
|
||||
},
|
||||
{
|
||||
CategoryID: 4,
|
||||
CategoryName: 'Dairy Products',
|
||||
Descriptions: 'Cheeses',
|
||||
},
|
||||
{
|
||||
CategoryID: 5,
|
||||
CategoryName: 'Grains/Cereals',
|
||||
Descriptions: 'Breads, crackers, pasta, and cereal',
|
||||
},
|
||||
{
|
||||
CategoryID: 6,
|
||||
CategoryName: 'Meat/Poultry',
|
||||
Descriptions: 'Prepared meats',
|
||||
},
|
||||
{
|
||||
CategoryID: 7,
|
||||
CategoryName: 'Produce',
|
||||
Descriptions: 'Dried fruit and bean curd',
|
||||
},
|
||||
{
|
||||
CategoryID: 8,
|
||||
CategoryName: 'Seafood',
|
||||
Descriptions: 'Seaweed and fish',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
expandChange: function (event) {
|
||||
event.dataItem[event.target.$props.expandField] = event.value;
|
||||
},
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
customSaveExcel: function (exportOptions) {
|
||||
const saveFn = (dataURL) => {
|
||||
saveAs(dataURL, exportOptions.fileName);
|
||||
};
|
||||
|
||||
const options = workbookOptions(exportOptions);
|
||||
const rows = options.sheets[0].rows;
|
||||
const headerOptions = rows[0].cells[0];
|
||||
|
||||
let altIdx = 0;
|
||||
let currentCategoryProducts;
|
||||
let currentRowIndex = null;
|
||||
this.categories.forEach((category) => {
|
||||
currentCategoryProducts = this.products.filter(
|
||||
(item) => item.CategoryID === category.CategoryID
|
||||
);
|
||||
rows.find((el, index) => {
|
||||
if (el.cells[0].value === currentCategoryProducts[0].CategoryID) {
|
||||
currentRowIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
// Add the Detail tables' data
|
||||
for (
|
||||
let productIdx = currentCategoryProducts.length - 1;
|
||||
productIdx >= 0;
|
||||
productIdx--
|
||||
) {
|
||||
const product = currentCategoryProducts[productIdx];
|
||||
rows.splice(currentRowIndex + 1, 0, {
|
||||
cells: [
|
||||
{},
|
||||
{ value: product.ProductID },
|
||||
{ value: product.ProductName },
|
||||
{ value: product.UnitPrice },
|
||||
{ value: product.UnitsInStock },
|
||||
],
|
||||
}); // Add all products of the current category
|
||||
}
|
||||
|
||||
// Apply color to the headers of the Detail tables
|
||||
rows.splice(currentRowIndex + 1, 0, {
|
||||
cells: [
|
||||
{},
|
||||
Object.assign({}, headerOptions, { value: 'Product ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Product Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'Unit Price' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units In Stock' }),
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
toDataURL(options).then(saveFn);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,198 @@
|
|||
<template>
|
||||
<KButton
|
||||
class="k-button k-primary"
|
||||
:title="'Export PDF'"
|
||||
@click="exportExcel"
|
||||
>
|
||||
Export the two Grids to Excel and save the data to two different sheets
|
||||
</KButton>
|
||||
<br />
|
||||
<br />
|
||||
<Grid ref="grid1" :columns="columns" :data-items="categories"> </Grid>
|
||||
<br />
|
||||
<br />
|
||||
<Grid ref="grid2" :columns="columnsGrid2" :data-items="grid2Data"> </Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { workbookOptions, toDataURL } from '@progress/kendo-vue-excel-export';
|
||||
import { saveAs } from '@progress/kendo-file-saver';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
KButton: Button,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
expandedItems: [],
|
||||
columns: [
|
||||
{ field: 'CategoryID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'CategoryName', title: 'Category Name' },
|
||||
{ field: 'Descriptions', title: 'Descriptions' },
|
||||
],
|
||||
columnsGrid2: [
|
||||
{ field: 'ProductID', editable: false, title: 'ID', width: '80px' },
|
||||
{ field: 'ProductName', title: 'Name' },
|
||||
{
|
||||
field: 'FirstOrderedOn',
|
||||
editor: 'date',
|
||||
title: 'First Ordered',
|
||||
format: '{0:d}',
|
||||
},
|
||||
{
|
||||
field: 'UnitsInStock',
|
||||
title: 'Units',
|
||||
width: '150px',
|
||||
editor: 'numeric',
|
||||
},
|
||||
{ field: 'Discontinued', title: 'Discontinued', editor: 'boolean' },
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
CategoryID: 1,
|
||||
CategoryName: 'Beverages',
|
||||
Descriptions: 'Soft drinks, coffees, teas, beers, and ales',
|
||||
},
|
||||
{
|
||||
CategoryID: 2,
|
||||
CategoryName: 'Condiments',
|
||||
Descriptions:
|
||||
'Sweet and savory sauces, relishes, spreads, and seasonings',
|
||||
},
|
||||
{
|
||||
CategoryID: 3,
|
||||
CategoryName: 'Confections',
|
||||
Descriptions: 'Desserts, candies, and sweet breads',
|
||||
},
|
||||
{
|
||||
CategoryID: 4,
|
||||
CategoryName: 'Dairy Products',
|
||||
Descriptions: 'Cheeses',
|
||||
},
|
||||
{
|
||||
CategoryID: 5,
|
||||
CategoryName: 'Grains/Cereals',
|
||||
Descriptions: 'Breads, crackers, pasta, and cereal',
|
||||
},
|
||||
{
|
||||
CategoryID: 6,
|
||||
CategoryName: 'Meat/Poultry',
|
||||
Descriptions: 'Prepared meats',
|
||||
},
|
||||
{
|
||||
CategoryID: 7,
|
||||
CategoryName: 'Produce',
|
||||
Descriptions: 'Dried fruit and bean curd',
|
||||
},
|
||||
{
|
||||
CategoryID: 8,
|
||||
CategoryName: 'Seafood',
|
||||
Descriptions: 'Seaweed and fish',
|
||||
},
|
||||
],
|
||||
grid2Data: [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: 'Chai',
|
||||
UnitsInStock: 39,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 20),
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: 'Chang',
|
||||
UnitsInStock: 17,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 7, 12),
|
||||
},
|
||||
{
|
||||
ProductID: 3,
|
||||
ProductName: 'Aniseed Syrup',
|
||||
UnitsInStock: 13,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 26),
|
||||
},
|
||||
{
|
||||
ProductID: 4,
|
||||
ProductName: 'Cajun Seasoning',
|
||||
UnitsInStock: 53,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 5,
|
||||
ProductName: 'Orange',
|
||||
UnitsInStock: 51,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 6,
|
||||
ProductName: 'Banana',
|
||||
UnitsInStock: 22,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 7,
|
||||
ProductName: 'Apple',
|
||||
UnitsInStock: 16,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 8,
|
||||
ProductName: 'Peach',
|
||||
UnitsInStock: 10,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
customSaveExcel: function (exportOptions) {
|
||||
const saveFn = (dataURL) => {
|
||||
saveAs(dataURL, exportOptions.fileName);
|
||||
};
|
||||
|
||||
const options = workbookOptions(exportOptions);
|
||||
const headerOptions = options.sheets[0].rows[0].cells[0];
|
||||
options.sheets.push({ rows: [] });
|
||||
const rows = options.sheets[1].rows;
|
||||
|
||||
rows.push({
|
||||
cells: [
|
||||
Object.assign({}, headerOptions, { value: 'ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'First Ordered' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units' }),
|
||||
Object.assign({}, headerOptions, { value: 'Discontinued' }),
|
||||
],
|
||||
});
|
||||
this.grid2Data.forEach((category) => {
|
||||
rows.push({
|
||||
cells: [
|
||||
{ value: category.ProductID },
|
||||
{ value: category.ProductName },
|
||||
{ value: category.FirstOrderedOn },
|
||||
{ value: category.UnitsInStock },
|
||||
{ value: category.Discontinued },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
toDataURL(options).then(saveFn);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,210 @@
|
|||
<template>
|
||||
<KButton
|
||||
class="k-button k-primary"
|
||||
:title="'Export PDF'"
|
||||
@click="exportExcel"
|
||||
>
|
||||
Export the two Grids to Excel and save the data to one sheet
|
||||
</KButton>
|
||||
<br />
|
||||
<br />
|
||||
<Grid ref="grid1" :columns="columns" :data-items="categories"> </Grid>
|
||||
<br />
|
||||
<br />
|
||||
<Grid ref="grid2" :columns="columnsGrid2" :data-items="grid2Data"> </Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { workbookOptions, toDataURL } from '@progress/kendo-vue-excel-export';
|
||||
import { saveAs } from '@progress/kendo-file-saver';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
KButton: Button,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
expandedItems: [],
|
||||
columns: [
|
||||
{ field: 'CategoryID', filterable: false, title: 'ID', width: '50px' },
|
||||
{ field: 'CategoryName', title: 'Category Name' },
|
||||
{ field: 'Descriptions', title: 'Descriptions' },
|
||||
],
|
||||
columnsGrid2: [
|
||||
{ field: 'ProductID', editable: false, title: 'ID', width: '80px' },
|
||||
{ field: 'ProductName', title: 'Name' },
|
||||
{
|
||||
field: 'FirstOrderedOn',
|
||||
editor: 'date',
|
||||
title: 'First Ordered',
|
||||
format: '{0:d}',
|
||||
},
|
||||
{
|
||||
field: 'UnitsInStock',
|
||||
title: 'Units',
|
||||
width: '150px',
|
||||
editor: 'numeric',
|
||||
},
|
||||
{ field: 'Discontinued', title: 'Discontinued', editor: 'boolean' },
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
CategoryID: 1,
|
||||
CategoryName: 'Beverages',
|
||||
Descriptions: 'Soft drinks, coffees, teas, beers, and ales',
|
||||
},
|
||||
{
|
||||
CategoryID: 2,
|
||||
CategoryName: 'Condiments',
|
||||
Descriptions:
|
||||
'Sweet and savory sauces, relishes, spreads, and seasonings',
|
||||
},
|
||||
{
|
||||
CategoryID: 3,
|
||||
CategoryName: 'Confections',
|
||||
Descriptions: 'Desserts, candies, and sweet breads',
|
||||
},
|
||||
{
|
||||
CategoryID: 4,
|
||||
CategoryName: 'Dairy Products',
|
||||
Descriptions: 'Cheeses',
|
||||
},
|
||||
{
|
||||
CategoryID: 5,
|
||||
CategoryName: 'Grains/Cereals',
|
||||
Descriptions: 'Breads, crackers, pasta, and cereal',
|
||||
},
|
||||
{
|
||||
CategoryID: 6,
|
||||
CategoryName: 'Meat/Poultry',
|
||||
Descriptions: 'Prepared meats',
|
||||
},
|
||||
{
|
||||
CategoryID: 7,
|
||||
CategoryName: 'Produce',
|
||||
Descriptions: 'Dried fruit and bean curd',
|
||||
},
|
||||
{
|
||||
CategoryID: 8,
|
||||
CategoryName: 'Seafood',
|
||||
Descriptions: 'Seaweed and fish',
|
||||
},
|
||||
],
|
||||
grid2Data: [
|
||||
{
|
||||
ProductID: 1,
|
||||
ProductName: 'Chai',
|
||||
UnitsInStock: 39,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 20),
|
||||
},
|
||||
{
|
||||
ProductID: 2,
|
||||
ProductName: 'Chang',
|
||||
UnitsInStock: 17,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 7, 12),
|
||||
},
|
||||
{
|
||||
ProductID: 3,
|
||||
ProductName: 'Aniseed Syrup',
|
||||
UnitsInStock: 13,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 8, 26),
|
||||
},
|
||||
{
|
||||
ProductID: 4,
|
||||
ProductName: 'Cajun Seasoning',
|
||||
UnitsInStock: 53,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 5,
|
||||
ProductName: 'Orange',
|
||||
UnitsInStock: 51,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 6,
|
||||
ProductName: 'Banana',
|
||||
UnitsInStock: 22,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 7,
|
||||
ProductName: 'Apple',
|
||||
UnitsInStock: 16,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
{
|
||||
ProductID: 8,
|
||||
ProductName: 'Peach',
|
||||
UnitsInStock: 10,
|
||||
Discontinued: false,
|
||||
FirstOrderedOn: new Date(1996, 9, 19),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
customSaveExcel: function (exportOptions) {
|
||||
const saveFn = (dataURL) => {
|
||||
saveAs(dataURL, exportOptions.fileName);
|
||||
};
|
||||
|
||||
const options = workbookOptions(exportOptions);
|
||||
const rows = options.sheets[0].rows;
|
||||
const headerOptions = rows[0].cells[0];
|
||||
|
||||
// Add two empty rows
|
||||
rows.push({
|
||||
cells: [{}, {}, {}],
|
||||
});
|
||||
rows.push({
|
||||
cells: [{}, {}, {}],
|
||||
});
|
||||
|
||||
rows.push({
|
||||
cells: [{ value: 'Below is the content of the second Grid' }, {}, {}],
|
||||
});
|
||||
|
||||
rows.push({
|
||||
cells: [
|
||||
Object.assign({}, headerOptions, { value: 'ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'First Ordered' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units' }),
|
||||
Object.assign({}, headerOptions, { value: 'Discontinued' }),
|
||||
],
|
||||
});
|
||||
this.grid2Data.forEach((category) => {
|
||||
rows.push({
|
||||
cells: [
|
||||
{ value: category.ProductID },
|
||||
{ value: category.ProductName },
|
||||
{ value: category.FirstOrderedOn },
|
||||
{ value: category.UnitsInStock },
|
||||
{ value: category.Discontinued },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
toDataURL(options).then(saveFn);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<div>
|
||||
<section :style='{ width: "200px", float: "left" }'>
|
||||
<p><strong>Street:</strong> {{dataItem.shipAddress.street}}</p>
|
||||
<p><strong>City:</strong> {{dataItem.shipAddress.city}}</p>
|
||||
<p><strong>Country:</strong> {{dataItem.shipAddress.country}}</p>
|
||||
<p><strong>Postal Code:</strong> {{dataItem.shipAddress.postalCode}}</p>
|
||||
</section>
|
||||
<Grid :style='{ width: "500px" }' :data-items="dataItem.details"></Grid>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
dataItem: Object
|
||||
},
|
||||
components: {
|
||||
'Grid': Grid
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"datepicker": {
|
||||
"toggleCalendar": "Alternar calendario"
|
||||
},
|
||||
"calendar": {
|
||||
"today": "Hoy"
|
||||
},
|
||||
"dateinput": {
|
||||
"increment": "Incrementar valor",
|
||||
"decrement": "Disminuir valor"
|
||||
},
|
||||
"numerictextbox": {
|
||||
"increment": "Incrementar valor",
|
||||
"decrement": "Disminuir valor"
|
||||
},
|
||||
"grid": {
|
||||
"groupPanelEmpty": "Arrastre el título de una columna y suéltelo aquí para agrupar por ese criterio",
|
||||
"noRecords": "No hay datos disponibles.",
|
||||
"pagerFirstPage": "Ir a la primera página",
|
||||
"pagerPreviousPage": "Ir a la página anterior",
|
||||
"pagerNextPage": "Ir a la página siguiente",
|
||||
"pagerLastPage": "Ir a la última página",
|
||||
"pagerPage": "Página",
|
||||
"pagerOf": "de",
|
||||
"pagerTotalPages": "{0}",
|
||||
"pagerItems": "ítems",
|
||||
"pagerInfo": "{0} - {1} de {2} ítems",
|
||||
"pagerItemsPerPage": "ítems por página",
|
||||
"filterEqOperator": "Es igual a",
|
||||
"filterNotEqOperator": "No es igual a",
|
||||
"filterIsNullOperator": "Es nulo",
|
||||
"filterIsNotNullOperator": "No es nulo",
|
||||
"filterIsEmptyOperator": "Está vacío",
|
||||
"filterIsNotEmptyOperator": "No está vacío",
|
||||
"filterStartsWithOperator": "Comienza con",
|
||||
"filterContainsOperator": "Contiene",
|
||||
"filterNotContainsOperator": "No contiene",
|
||||
"filterEndsWithOperator": "Termina en",
|
||||
"filterGteOperator": "Es mayor o igual que",
|
||||
"filterGtOperator": "Es mayor que",
|
||||
"filterLteOperator": "Es menor o igual que",
|
||||
"filterLtOperator": "Es menor o igual que",
|
||||
"filterIsTrue": "Sí",
|
||||
"filterIsFalse": "No",
|
||||
"filterBooleanAll": "(Todas)",
|
||||
"filterAfterOrEqualOperator": "Es posterior o igual a",
|
||||
"filterAfterOperator": "Es posterior",
|
||||
"filterBeforeOperator": "Es anterior",
|
||||
"filterBeforeOrEqualOperator": "Es anterior o igual a",
|
||||
"filterFilterButton": "Filtrar",
|
||||
"filterClearButton": "Limpiar filtros",
|
||||
"filterAndLogic": "Y",
|
||||
"filterOrLogic": "O"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,228 @@
|
|||
<template>
|
||||
<localization :language="currentLocale.language">
|
||||
<intl :locale="currentLocale.locale">
|
||||
<div>
|
||||
<pdfexport ref="gridPdfExport">
|
||||
<Grid
|
||||
:style="{ height: '700px' }"
|
||||
:sortable="sortable"
|
||||
:filterable="filterable"
|
||||
:groupable="groupable"
|
||||
:reorderable="reorderable"
|
||||
:pageable="{ buttonCount: 4, pageSizes: true }"
|
||||
:data-items="dataResult"
|
||||
:skip="skip"
|
||||
:take="take"
|
||||
:sort="sort"
|
||||
:group="group"
|
||||
:filter="filter"
|
||||
:columns="columns"
|
||||
@datastatechange="dataStateChange"
|
||||
:detail="detailComponent"
|
||||
:expand-field="'expanded'"
|
||||
@expandchange="expandChange"
|
||||
@columnreorder="columnReorder"
|
||||
>
|
||||
<template v-slot:myTemplate="{ props }">
|
||||
<custom :data-item="props.dataItem" />
|
||||
</template>
|
||||
<toolbar>
|
||||
Locale:
|
||||
<dropdownlist
|
||||
:value="currentLocale"
|
||||
:text-field="'language'"
|
||||
@change="dropDownChange"
|
||||
:data-items="locales"
|
||||
></dropdownlist>
|
||||
<kbutton
|
||||
title="Export to Excel"
|
||||
:theme-color="'primary'"
|
||||
@click="exportExcel"
|
||||
>Export to Excel</kbutton>
|
||||
<kbutton :theme-color="'primary'" @click="exportPDF">Export to PDF</kbutton>
|
||||
</toolbar>
|
||||
</Grid>
|
||||
</pdfexport>
|
||||
</div>
|
||||
</intl>
|
||||
</localization>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid, GridToolbar } from '@progress/kendo-vue-grid';
|
||||
import { DropDownList } from '@progress/kendo-vue-dropdowns';
|
||||
import { Button } from '@progress/kendo-vue-buttons';
|
||||
import { GridPdfExport } from '@progress/kendo-vue-pdf';
|
||||
import { saveExcel } from '@progress/kendo-vue-excel-export';
|
||||
import {
|
||||
IntlProvider,
|
||||
load,
|
||||
LocalizationProvider,
|
||||
loadMessages,
|
||||
IntlService,
|
||||
} from '@progress/kendo-vue-intl';
|
||||
import DetailComponent from './DetailComponent';
|
||||
|
||||
import likelySubtags from 'cldr-core/supplemental/likelySubtags.json';
|
||||
import currencyData from 'cldr-core/supplemental/currencyData.json';
|
||||
import weekData from 'cldr-core/supplemental/weekData.json';
|
||||
|
||||
import numbers from 'cldr-numbers-full/main/es/numbers.json';
|
||||
import currencies from 'cldr-numbers-full/main/es/currencies.json';
|
||||
import caGregorian from 'cldr-dates-full/main/es/ca-gregorian.json';
|
||||
import dateFields from 'cldr-dates-full/main/es/dateFields.json';
|
||||
import timeZoneNames from 'cldr-dates-full/main/es/timeZoneNames.json';
|
||||
|
||||
load(
|
||||
likelySubtags,
|
||||
currencyData,
|
||||
weekData,
|
||||
numbers,
|
||||
currencies,
|
||||
caGregorian,
|
||||
dateFields,
|
||||
timeZoneNames
|
||||
);
|
||||
|
||||
import esMessages from './es.json';
|
||||
loadMessages(esMessages, 'es-ES');
|
||||
|
||||
import { process } from '@progress/kendo-data-query';
|
||||
import orders from './orders.json';
|
||||
|
||||
const DATE_FORMAT = 'yyyy-mm-dd hh:mm:ss.SSS';
|
||||
const intl = new IntlService();
|
||||
|
||||
orders.forEach((o) => {
|
||||
o.orderDate = intl.parseDate(o.orderDate, DATE_FORMAT);
|
||||
o.shippedDate =
|
||||
o.shippedDate === 'NULL'
|
||||
? undefined
|
||||
: intl.parseDate(o.shippedDate, DATE_FORMAT);
|
||||
});
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
pdfexport: GridPdfExport,
|
||||
toolbar: GridToolbar,
|
||||
dropdownlist: DropDownList,
|
||||
intl: IntlProvider,
|
||||
localization: LocalizationProvider,
|
||||
custom: DetailComponent,
|
||||
kbutton: Button,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
skip: 0,
|
||||
take: 20,
|
||||
sort: [{ field: 'orderDate', dir: 'desc' }],
|
||||
group: [{ field: 'customerID' }],
|
||||
filter: null,
|
||||
dataResult: [],
|
||||
locales: [
|
||||
{
|
||||
language: 'en-US',
|
||||
locale: 'en',
|
||||
},
|
||||
{
|
||||
language: 'es-ES',
|
||||
locale: 'es',
|
||||
},
|
||||
],
|
||||
currentLocale: null,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
reorderable: true,
|
||||
detailComponent: 'myTemplate',
|
||||
columns: [
|
||||
{ field: 'customerID', width: '200px' },
|
||||
{ field: 'orderDate', filter: 'date', format: '{0:D}', width: '300px' },
|
||||
{ field: 'shipName', width: '280px' },
|
||||
{ field: 'freight', filter: 'numeric', width: '200px' },
|
||||
{
|
||||
field: 'shippedDate',
|
||||
filter: 'date',
|
||||
format: '{0:D}',
|
||||
width: '300px',
|
||||
},
|
||||
{ field: 'employeeID', filter: 'numeric', width: '200px' },
|
||||
{
|
||||
field: 'orderID',
|
||||
filterable: 'false',
|
||||
title: 'ID',
|
||||
width: '90px',
|
||||
locked: 'true',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.currentLocale = this.locales[0];
|
||||
const dataState = {
|
||||
skip: this.skip,
|
||||
take: this.take,
|
||||
sort: this.sort,
|
||||
group: this.group,
|
||||
};
|
||||
|
||||
this.dataResult = process(orders, dataState);
|
||||
},
|
||||
methods: {
|
||||
createAppState: function (dataState) {
|
||||
this.take = dataState.take;
|
||||
this.skip = dataState.skip;
|
||||
if (dataState.group) {
|
||||
dataState.group.map((group) => (group.aggregates = this.aggregates));
|
||||
}
|
||||
this.group = dataState.group;
|
||||
this.filter = dataState.filter;
|
||||
this.sort = dataState.sort;
|
||||
},
|
||||
dataStateChange(event) {
|
||||
this.createAppState(event.data);
|
||||
this.dataResult = process(orders, {
|
||||
skip: this.skip,
|
||||
take: this.take,
|
||||
sort: this.sort,
|
||||
filter: this.filter,
|
||||
group: this.group,
|
||||
});
|
||||
},
|
||||
expandChange(event) {
|
||||
const isExpanded =
|
||||
event.dataItem.expanded === undefined
|
||||
? event.dataItem.aggregates
|
||||
: event.dataItem.expanded;
|
||||
event.dataItem.expanded = !isExpanded;
|
||||
},
|
||||
exportExcel() {
|
||||
saveExcel({
|
||||
data: orders,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
exportPDF() {
|
||||
const tempSort = this.sort;
|
||||
this.sort = null;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.gridPdfExport.save(
|
||||
process(orders, { skip: this.skip, take: this.take })
|
||||
);
|
||||
this.sort = tempSort;
|
||||
});
|
||||
},
|
||||
pageChangeHandler: function (event) {
|
||||
this.skip = event.page.skip;
|
||||
this.take = event.page.take;
|
||||
},
|
||||
columnReorder: function (options) {
|
||||
this.columns = options.columns;
|
||||
},
|
||||
dropDownChange: function (e) {
|
||||
this.currentLocale = e.target.value;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<Grid
|
||||
:style="{ height: '400px', width: '500px' }"
|
||||
:data-items="products"
|
||||
:reorderable="true"
|
||||
@columnreorder="columnReorder"
|
||||
:columns="columns"
|
||||
>
|
||||
<template v-slot:myLockedCell="{ props }">
|
||||
<td
|
||||
:colspan="props.colspan"
|
||||
:class="props.class"
|
||||
:role="props.role"
|
||||
:data-grid-col-index="props['data-grid-col-index']"
|
||||
:aria-selected="props['aria-selected']"
|
||||
>
|
||||
<b>{{ props.dataItem[props.field] }}</b>
|
||||
</td>
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { products } from './products';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
products: this.createRandomData(),
|
||||
columns: [
|
||||
{
|
||||
field: 'ProductID',
|
||||
title: 'ID',
|
||||
width: '45px',
|
||||
cell: 'myLockedCell',
|
||||
locked: true,
|
||||
},
|
||||
{
|
||||
field: 'ProductName',
|
||||
title: 'Name',
|
||||
width: '250px',
|
||||
},
|
||||
{ field: 'Category.CategoryName', title: 'CategoryName' },
|
||||
{ field: 'UnitPrice', title: 'Price', width: '90px' },
|
||||
{ field: 'UnitsInStock', title: 'In stock', width: '90px' },
|
||||
{ field: 'UnitsOnOrder', title: 'On order', width: '90px' },
|
||||
{
|
||||
field: 'Discontinued',
|
||||
locked: true,
|
||||
width: '120px',
|
||||
cell: 'myLockedCell',
|
||||
},
|
||||
{
|
||||
field: 'QuantityPerUnit',
|
||||
title: 'Additional details',
|
||||
width: '250px',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
columnReorder: function (options) {
|
||||
this.columns = options.columns;
|
||||
},
|
||||
createRandomData() {
|
||||
return products;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<td @dragover="dragOver">
|
||||
<span class="k-icon k-i-reorder"
|
||||
draggable="true"
|
||||
style="cursor: 'move'"
|
||||
@dragstart="dragStart"
|
||||
@dragend="dragEnd">
|
||||
</span>
|
||||
</td>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
emits:{
|
||||
dragover: null,
|
||||
dragstart: null,
|
||||
dragend: null
|
||||
},
|
||||
props: {
|
||||
dataItem: Object
|
||||
},
|
||||
methods: {
|
||||
dragOver(e){
|
||||
this.$emit('dragover', this.dataItem);
|
||||
},
|
||||
dragStart(e) {
|
||||
this.$emit('dragstart', this.dataItem);
|
||||
},
|
||||
dragEnd(e) {
|
||||
this.$emit('dragend');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<Grid
|
||||
:data-items="items"
|
||||
:selected-field="selectedField"
|
||||
:columns="columns">
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :data-item="props.dataItem"
|
||||
@dragover="reorder"
|
||||
@dragstart="setActive"
|
||||
@dragend="updateRemote"/>
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import CustomCell from './CustomCell';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Grid': Grid,
|
||||
'custom': CustomCell
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selectedField: 'selected',
|
||||
items: [],
|
||||
columns: [
|
||||
{ field: 'ProductID', title: '', cell: 'myTemplate', width: '80px', title: 'Reorder' },
|
||||
{ field: 'ProductID'},
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'UnitPrice', title: 'Unit Price' }
|
||||
],
|
||||
activeItem: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
createRandomData(count) {
|
||||
const productNames = ['Chai', 'Chang', 'Syrup', 'Apple', 'Orange', 'Banana', 'Lemon', 'Pineapple', 'Tea', 'Milk'];
|
||||
const unitPrices = [12.5, 10.1, 5.3, 7, 22.53, 16.22, 20, 50, 100, 120]
|
||||
|
||||
return Array(count).fill({}).map((_, idx) => ({
|
||||
ProductID: idx + 1,
|
||||
ProductName: productNames[Math.floor(Math.random() * productNames.length)],
|
||||
UnitPrice: unitPrices[Math.floor(Math.random() * unitPrices.length)]
|
||||
}));
|
||||
},
|
||||
reorder(dataItem) {
|
||||
let that = this;
|
||||
|
||||
if (that.activeItem === dataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
let reorderedData = this.items.slice();
|
||||
let prevIndex = reorderedData.findIndex(p => (p === that.activeItem));
|
||||
let nextIndex = reorderedData.findIndex(p => (p === dataItem));
|
||||
reorderedData.splice(prevIndex, 1);
|
||||
reorderedData.splice(nextIndex, 0, this.activeItem);
|
||||
|
||||
that.items = reorderedData;
|
||||
},
|
||||
setActive(dataItem) {
|
||||
this.activeItem = dataItem;
|
||||
this.activeItem.selected = true;
|
||||
},
|
||||
updateRemote() {
|
||||
console.log('in drag end');
|
||||
this.activeItem = {};
|
||||
// Send request to remote to update the source order
|
||||
|
||||
this.items = this.items.map(i => {
|
||||
i.selected = undefined;
|
||||
return i;
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.items = this.createRandomData(10);
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<Grid :data-items="products" :filterable="true" :filter="filter" @filterchange="filterChange" :columns="columns"
|
||||
:loader="loader">
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { filterBy } from '@progress/kendo-data-query';
|
||||
import { sampleProducts } from './products';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid: Grid,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
sampleProducts: sampleProducts,
|
||||
loader: false,
|
||||
filter: {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
{ field: 'UnitPrice', operator: 'neq', value: 18 },
|
||||
{
|
||||
field: 'FirstOrderedOn',
|
||||
operator: 'gte',
|
||||
value: new Date('1996-10-10'),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
products: function () {
|
||||
return filterBy(this.sampleProducts, this.filter);
|
||||
},
|
||||
columns: function () {
|
||||
const columns = [
|
||||
{
|
||||
field: 'ProductID',
|
||||
filterable: false,
|
||||
title: 'Product ID',
|
||||
width: '50px',
|
||||
},
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'FirstOrderedOn', filter: 'date', title: 'First Ordered On' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'Discontinued', filter: 'boolean', title: 'Discontinued' },
|
||||
].map((col) => {
|
||||
return this.isFiltered(col)
|
||||
? {
|
||||
...col,
|
||||
headerClassName: 'filtered',
|
||||
}
|
||||
: col;
|
||||
});
|
||||
return columns;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isFiltered(col) {
|
||||
const filters = this.filter ? this.filter.filters : [];
|
||||
return filters.findIndex((f) => f.field === col.field) >= 0;
|
||||
},
|
||||
filterChange: function (ev) {
|
||||
this.loader = true;
|
||||
// The idea behind using the following setTimeout method is to
|
||||
// demonstrate how we can show a loader while fetching data.
|
||||
// In real-life scenarios with remote data binding, the 'loader'
|
||||
// property should be updated before making a server request
|
||||
// and after the request completes.
|
||||
setTimeout(() => {
|
||||
this.filter = ev.filter;
|
||||
this.loader = false;
|
||||
}, 300);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.filtered {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,184 @@
|
|||
const sampleProducts = [
|
||||
{
|
||||
"ProductID": 1,
|
||||
"ProductName": "Chai",
|
||||
"SupplierID": 1,
|
||||
"CategoryID": 1,
|
||||
"QuantityPerUnit": "10 boxes x 20 bags",
|
||||
"UnitPrice": 18,
|
||||
"UnitsInStock": 39,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 10,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 1,
|
||||
"CategoryName": "Beverages",
|
||||
"Description": "Soft drinks, coffees, teas, beers, and ales"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 8, 20)
|
||||
},
|
||||
{
|
||||
"ProductID": 2,
|
||||
"ProductName": "Chang",
|
||||
"SupplierID": 1,
|
||||
"CategoryID": 1,
|
||||
"QuantityPerUnit": "24 - 12 oz bottles",
|
||||
"UnitPrice": 19,
|
||||
"UnitsInStock": 17,
|
||||
"UnitsOnOrder": 40,
|
||||
"ReorderLevel": 25,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 1,
|
||||
"CategoryName": "Beverages",
|
||||
"Description": "Soft drinks, coffees, teas, beers, and ales"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 7, 12)
|
||||
},
|
||||
{
|
||||
"ProductID": 3,
|
||||
"ProductName": "Aniseed Syrup",
|
||||
"SupplierID": 1,
|
||||
"CategoryID": 2,
|
||||
"QuantityPerUnit": "12 - 550 ml bottles",
|
||||
"UnitPrice": 10,
|
||||
"UnitsInStock": 13,
|
||||
"UnitsOnOrder": 70,
|
||||
"ReorderLevel": 25,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 2,
|
||||
"CategoryName": "Condiments",
|
||||
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 8, 26)
|
||||
},
|
||||
{
|
||||
"ProductID": 4,
|
||||
"ProductName": "Chef Anton's Cajun Seasoning",
|
||||
"SupplierID": 2,
|
||||
"CategoryID": 2,
|
||||
"QuantityPerUnit": "48 - 6 oz jars",
|
||||
"UnitPrice": 22,
|
||||
"UnitsInStock": 53,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 0,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 2,
|
||||
"CategoryName": "Condiments",
|
||||
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 9, 19)
|
||||
},
|
||||
{
|
||||
"ProductID": 5,
|
||||
"ProductName": "Chef Anton's Gumbo Mix",
|
||||
"SupplierID": 2,
|
||||
"CategoryID": 2,
|
||||
"QuantityPerUnit": "36 boxes",
|
||||
"UnitPrice": 21.35,
|
||||
"UnitsInStock": 0,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 0,
|
||||
"Discontinued": true,
|
||||
"Category": {
|
||||
"CategoryID": 2,
|
||||
"CategoryName": "Condiments",
|
||||
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 7, 17)
|
||||
},
|
||||
{
|
||||
"ProductID": 6,
|
||||
"ProductName": "Grandma's Boysenberry Spread",
|
||||
"SupplierID": 3,
|
||||
"CategoryID": 2,
|
||||
"QuantityPerUnit": "12 - 8 oz jars",
|
||||
"UnitPrice": 25,
|
||||
"UnitsInStock": 120,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 25,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 2,
|
||||
"CategoryName": "Condiments",
|
||||
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 9, 19)
|
||||
},
|
||||
{
|
||||
"ProductID": 7,
|
||||
"ProductName": "Uncle Bob's Organic Dried Pears",
|
||||
"SupplierID": 3,
|
||||
"CategoryID": 7,
|
||||
"QuantityPerUnit": "12 - 1 lb pkgs.",
|
||||
"UnitPrice": 30,
|
||||
"UnitsInStock": 15,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 10,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 7,
|
||||
"CategoryName": "Produce",
|
||||
"Description": "Dried fruit and bean curd"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 7, 22)
|
||||
},
|
||||
{
|
||||
"ProductID": 8,
|
||||
"ProductName": "Northwoods Cranberry Sauce",
|
||||
"SupplierID": 3,
|
||||
"CategoryID": 2,
|
||||
"QuantityPerUnit": "12 - 12 oz jars",
|
||||
"UnitPrice": 40,
|
||||
"UnitsInStock": 6,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 0,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 2,
|
||||
"CategoryName": "Condiments",
|
||||
"Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 11, 1)
|
||||
},
|
||||
{
|
||||
"ProductID": 9,
|
||||
"ProductName": "Mishi Kobe Niku",
|
||||
"SupplierID": 4,
|
||||
"CategoryID": 6,
|
||||
"QuantityPerUnit": "18 - 500 g pkgs.",
|
||||
"UnitPrice": 97,
|
||||
"UnitsInStock": 29,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 0,
|
||||
"Discontinued": true,
|
||||
"Category": {
|
||||
"CategoryID": 6,
|
||||
"CategoryName": "Meat/Poultry",
|
||||
"Description": "Prepared meats"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1997, 1, 21)
|
||||
},
|
||||
{
|
||||
"ProductID": 10,
|
||||
"ProductName": "Ikura",
|
||||
"SupplierID": 4,
|
||||
"CategoryID": 8,
|
||||
"QuantityPerUnit": "12 - 200 ml jars",
|
||||
"UnitPrice": 31,
|
||||
"UnitsInStock": 31,
|
||||
"UnitsOnOrder": 0,
|
||||
"ReorderLevel": 0,
|
||||
"Discontinued": false,
|
||||
"Category": {
|
||||
"CategoryID": 8,
|
||||
"CategoryName": "Seafood",
|
||||
"Description": "Seaweed and fish"
|
||||
},
|
||||
"FirstOrderedOn": new Date(1996, 8, 5)
|
||||
}
|
||||
];
|
||||
|
||||
export { sampleProducts };
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<Grid
|
||||
:data-items="products"
|
||||
:columns="columns"
|
||||
:cell-render="myCellTemplate">
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<td :rowspan=2 v-if="props.field === 'Discontinued' && props.dataItem.ProductID % 2 !== 0">{{ getNestedValue(props.field, props.dataItem) }}</td>
|
||||
|
||||
<td v-else-if="props.field !== 'Discontinued'" :class="props.className">{{ getNestedValue(props.field, props.dataItem) }}</td>
|
||||
</template>
|
||||
</Grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import products from "./products.json";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'Grid': Grid
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
products: products,
|
||||
myCellTemplate: 'myTemplate',
|
||||
columns: [
|
||||
{ field: 'ProductID', title: 'Product ID', width:'50px'},
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'Category.CategoryName', title: 'CategoryName'},
|
||||
{ field: 'UnitPrice', title: 'Unit Price'},
|
||||
{ field: 'UnitsInStock', title: 'In Stock'},
|
||||
{ field: 'Discontinued', title: 'Discontinued'}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNestedValue: function(fieldName, dataItem) {
|
||||
const path = fieldName.split('.');
|
||||
let data = dataItem;
|
||||
path.forEach((p) => {
|
||||
data = data ? data[p] : undefined;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<grid
|
||||
:style="{height: '280px'}"
|
||||
:data-items="items"
|
||||
:columns="columns">
|
||||
<template v-slot:myTemplate="{props, listeners}">
|
||||
<td :class="props.className" v-html="getNestedValue(props.field, props.dataItem)"></td>
|
||||
</template>
|
||||
</grid>
|
||||
</template>
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'grid': Grid
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
columns: [
|
||||
{ field: 'ProductID'},
|
||||
{ field: 'ProductName', title: 'Product Name', cell: 'myTemplate' },
|
||||
{ field: 'UnitPrice', title: 'Unit Price' }
|
||||
],
|
||||
items: [{
|
||||
"ProductID": 1,
|
||||
"ProductName": "This is <b>BOLD text</b>",
|
||||
"UnitPrice": 18.0000,
|
||||
},
|
||||
{
|
||||
"ProductID": 2,
|
||||
"ProductName": "Check <span style='color: red; font-weight: bold'>this styled text</span>",
|
||||
"UnitPrice": 19.0000,
|
||||
},
|
||||
{
|
||||
"ProductID": 3,
|
||||
"ProductName": "hello my name is <strong> Giuseppe </strong>",
|
||||
"UnitPrice": 10.0000,
|
||||
},
|
||||
{
|
||||
"ProductID": 4,
|
||||
"ProductName": "<i>Chef Anton's </i>Cajun Seasoning",
|
||||
"UnitPrice": 22.0000,
|
||||
},
|
||||
{
|
||||
"ProductID": 5,
|
||||
"ProductName": "<span style='color: green'> This is green text</span>",
|
||||
"UnitPrice": 22.0000,
|
||||
}]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getNestedValue: function(fieldName, dataItem) {
|
||||
const path = fieldName.split('.');
|
||||
let data = dataItem;
|
||||
path.forEach((p) => {
|
||||
data = data ? data[p] : undefined;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
|
@ -0,0 +1,847 @@
|
|||
const baseData = [
|
||||
{
|
||||
"TaskID": 4,
|
||||
"OwnerID": 2,
|
||||
"Title": "Bowling tournament",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-09T21:00:00.000Z",
|
||||
"End": "2013-06-10T00:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 5,
|
||||
"OwnerID": 2,
|
||||
"Title": "Take the dog to the vet",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-10T07:00:00.000Z",
|
||||
"End": "2013-06-10T08:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 6,
|
||||
"OwnerID": 2,
|
||||
"Title": "Call Charlie about the project",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-11T11:30:00.000Z",
|
||||
"End": "2013-06-11T13:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 7,
|
||||
"OwnerID": 3,
|
||||
"Title": "Meeting with Alex",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-12T11:00:00.000Z",
|
||||
"End": "2013-06-12T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 9,
|
||||
"OwnerID": 2,
|
||||
"Title": "Alex's Birthday",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-14T02:00:00.000Z",
|
||||
"End": "2013-06-14T02:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 12,
|
||||
"OwnerID": 2,
|
||||
"Title": "Car Service",
|
||||
"RoomID": 1,
|
||||
"Description": "Might come to work later!",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T08:30:00.000Z",
|
||||
"End": "2013-06-24T10:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 14,
|
||||
"OwnerID": 3,
|
||||
"RoomID": 2,
|
||||
"PersonID": 3,
|
||||
"Title": "Replace the printer on the 1st floor",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T10:00:00.000Z",
|
||||
"End": "2013-06-24T11:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 15,
|
||||
"OwnerID": 1,
|
||||
"Title": "Attending HR Conference",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T00:00:00.000Z",
|
||||
"End": "2013-06-26T00:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 16,
|
||||
"OwnerID": 1,
|
||||
"Title": "Business Lunch with Gregory Watkins",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T12:00:00.000Z",
|
||||
"End": "2013-06-25T13:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 17,
|
||||
"OwnerID": 1,
|
||||
"Title": "Breakfast with CFO and COO",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T08:30:00.000Z",
|
||||
"End": "2013-06-27T09:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 18,
|
||||
"OwnerID": 1,
|
||||
"Title": "Job Interview - Mathew Stevens",
|
||||
"Description": "Junior Researcher",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T10:00:00.000Z",
|
||||
"End": "2013-06-27T11:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 19,
|
||||
"OwnerID": 1,
|
||||
"Title": "Review CVs with Tim",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T11:00:00.000Z",
|
||||
"End": "2013-06-27T11:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 20,
|
||||
"OwnerID": 1,
|
||||
"Title": "Lunch with Monica",
|
||||
"Description": "Discuss the Employee handbook",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T12:00:00.000Z",
|
||||
"End": "2013-06-27T13:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 21,
|
||||
"OwnerID": 1,
|
||||
"Title": "Job Interview - John Stewart",
|
||||
"Description": "Accountant",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T14:00:00.000Z",
|
||||
"End": "2013-06-27T15:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 22,
|
||||
"OwnerID": 1,
|
||||
"Title": "Job Interview - Mary Smith",
|
||||
"Description": "Accountant",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T15:30:00.000Z",
|
||||
"End": "2013-06-27T16:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 24,
|
||||
"OwnerID": 3,
|
||||
"Title": "Register new Access Cards",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T12:00:00.000Z",
|
||||
"End": "2013-06-24T12:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 25,
|
||||
"OwnerID": 1,
|
||||
"Title": "HR Lecture",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-04T19:00:00.000Z",
|
||||
"End": "2013-06-04T21:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "FREQ=WEEKLY;BYDAY=TU,TH",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 26,
|
||||
"OwnerID": 1,
|
||||
"Title": "Dentist",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T08:00:00.000Z",
|
||||
"End": "2013-06-28T09:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 27,
|
||||
"OwnerID": 1,
|
||||
"Title": "Job Interview - Laura Bailey",
|
||||
"Description": "Helpdesk",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T09:30:00.000Z",
|
||||
"End": "2013-06-28T10:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 28,
|
||||
"OwnerID": 1,
|
||||
"Title": "Job Interview - Jenny Baxter",
|
||||
"Description": "Helpdesk",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T11:00:00.000Z",
|
||||
"End": "2013-06-28T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 31,
|
||||
"OwnerID": 1,
|
||||
"Title": "Team building prep tasks",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T14:00:00.000Z",
|
||||
"End": "2013-06-28T17:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 32,
|
||||
"OwnerID": 2,
|
||||
"RoomID": 2,
|
||||
"Title": "Job Interview - Bernard Atkins",
|
||||
"Description": "Helpdesk",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T13:30:00.000Z",
|
||||
"End": "2013-06-24T14:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 34,
|
||||
"OwnerID": 1,
|
||||
"Title": "Review Job Applications",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T15:00:00.000Z",
|
||||
"End": "2013-06-24T17:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 35,
|
||||
"OwnerID": 1,
|
||||
"Title": "Grand Canyon tour",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-23T00:00:00.000Z",
|
||||
"End": "2013-06-23T00:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 40,
|
||||
"OwnerID": 3,
|
||||
"Title": "Install new laptops in conference rooms",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T13:30:00.000Z",
|
||||
"End": "2013-06-24T15:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 66,
|
||||
"OwnerID": 3,
|
||||
"Title": "Bob's Birthday",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-29T08:00:00.000Z",
|
||||
"End": "2013-06-29T06:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 68,
|
||||
"OwnerID": 1,
|
||||
"RoomID": 2,
|
||||
"Title": "Breakfast with Tom",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T09:45:00.000Z",
|
||||
"End": "2013-06-24T11:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 69,
|
||||
"OwnerID": 2,
|
||||
"Title": "Team planning meeting",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T10:00:00.000Z",
|
||||
"End": "2013-06-24T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 70,
|
||||
"OwnerID": 2,
|
||||
"Title": "Support Phone Call",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-24T16:00:00.000Z",
|
||||
"End": "2013-06-24T16:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 71,
|
||||
"OwnerID": 2,
|
||||
"Title": "Business breakfast with Caroline",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T09:00:00.000Z",
|
||||
"End": "2013-06-25T10:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 72,
|
||||
"OwnerID": 2,
|
||||
"Title": "Discuss preojects' deadlines",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T11:00:00.000Z",
|
||||
"End": "2013-06-25T11:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 73,
|
||||
"OwnerID": 2,
|
||||
"Title": "Support Meeting",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T15:00:00.000Z",
|
||||
"End": "2013-06-25T16:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 74,
|
||||
"OwnerID": 2,
|
||||
"Title": "Dine with Mathew",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T18:30:00.000Z",
|
||||
"End": "2013-06-25T20:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 79,
|
||||
"OwnerID": 2,
|
||||
"Title": "Banking",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-26T09:00:00.000Z",
|
||||
"End": "2013-06-26T10:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 80,
|
||||
"OwnerID": 3,
|
||||
"Title": "Software updates",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T10:00:00.000Z",
|
||||
"End": "2013-06-25T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 81,
|
||||
"OwnerID": 3,
|
||||
"Title": "UPS maintenance",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-25T16:30:00.000Z",
|
||||
"End": "2013-06-25T18:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 82,
|
||||
"OwnerID": 2,
|
||||
"Title": "Support Call",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-26T11:30:00.000Z",
|
||||
"End": "2013-06-26T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 83,
|
||||
"OwnerID": 3,
|
||||
"Title": "Phone Sync with NY office ",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-26T13:30:00.000Z",
|
||||
"End": "2013-06-26T14:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 84,
|
||||
"OwnerID": 3,
|
||||
"Title": "Phone Sync with Boston Office",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-26T15:00:00.000Z",
|
||||
"End": "2013-06-26T16:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 85,
|
||||
"OwnerID": 3,
|
||||
"Title": "Server maintenance",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-26T18:30:00.000Z",
|
||||
"End": "2013-06-26T21:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": true
|
||||
},
|
||||
{
|
||||
"TaskID": 86,
|
||||
"OwnerID": 2,
|
||||
"Title": "Status meeting",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T13:30:00.000Z",
|
||||
"End": "2013-06-28T15:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 87,
|
||||
"OwnerID": 3,
|
||||
"Title": "Helpdesk status meeting",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T10:30:00.000Z",
|
||||
"End": "2013-06-27T11:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 88,
|
||||
"OwnerID": 2,
|
||||
"Title": "Business Lunch",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T12:00:00.000Z",
|
||||
"End": "2013-06-27T13:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 89,
|
||||
"OwnerID": 3,
|
||||
"Title": "Employee database update",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T14:00:00.000Z",
|
||||
"End": "2013-06-27T15:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 90,
|
||||
"OwnerID": 3,
|
||||
"Title": "Website upload",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T07:30:00.000Z",
|
||||
"End": "2013-06-27T08:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 91,
|
||||
"OwnerID": 2,
|
||||
"Title": "Meeting with marketing guys",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-27T17:00:00.000Z",
|
||||
"End": "2013-06-27T18:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 92,
|
||||
"OwnerID": 3,
|
||||
"Title": "Meeting with Internet provider",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-28T10:30:00.000Z",
|
||||
"End": "2013-06-28T11:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 93,
|
||||
"OwnerID": 3,
|
||||
"Title": "Bob's Birthday Party",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-29T20:00:00.000Z",
|
||||
"End": "2013-06-29T23:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": null,
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 95,
|
||||
"OwnerID": 2,
|
||||
"Title": "Dance Practice",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-03T18:30:00.000Z",
|
||||
"End": "2013-06-03T20:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "FREQ=WEEKLY;BYDAY=MO,WE",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 114,
|
||||
"OwnerID": 3,
|
||||
"Title": "Software updates",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-04T09:00:00.000Z",
|
||||
"End": "2013-06-04T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 115,
|
||||
"OwnerID": 1,
|
||||
"Title": "Breakfast at Starbucks",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-04T08:00:00.000Z",
|
||||
"End": "2013-06-04T09:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 116,
|
||||
"OwnerID": 2,
|
||||
"Title": "Performance review",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-04T14:00:00.000Z",
|
||||
"End": "2013-06-04T17:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 118,
|
||||
"OwnerID": 1,
|
||||
"Title": "HR seminar preparation",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-05T10:00:00.000Z",
|
||||
"End": "2013-06-05T12:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 119,
|
||||
"OwnerID": 3,
|
||||
"Title": "Helpdesk weekly meeting",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-05T15:00:00.000Z",
|
||||
"End": "2013-06-05T16:00:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "FREQ=WEEKLY;BYDAY=WE",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
},
|
||||
{
|
||||
"TaskID": 120,
|
||||
"OwnerID": 3,
|
||||
"Title": "Website upload",
|
||||
"Description": "",
|
||||
"StartTimezone": null,
|
||||
"Start": "2013-06-07T07:00:00.000Z",
|
||||
"End": "2013-06-07T08:30:00.000Z",
|
||||
"EndTimezone": null,
|
||||
"RecurrenceRule": "",
|
||||
"RecurrenceID": null,
|
||||
"RecurrenceException": null,
|
||||
"isAllDay": false
|
||||
}
|
||||
];
|
||||
|
||||
export const customModelFields = {
|
||||
id: 'TaskID',
|
||||
title: 'Title',
|
||||
description: 'Description',
|
||||
start: 'Start',
|
||||
end: 'End',
|
||||
recurrenceRule: 'RecurrenceRule',
|
||||
recurrenceId: 'RecurrenceID',
|
||||
recurrenceExceptions: 'RecurrenceException'
|
||||
};
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
const parseAdjust = (eventDate) => {
|
||||
const date = new Date(eventDate);
|
||||
date.setFullYear(currentYear);
|
||||
return date;
|
||||
};
|
||||
|
||||
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
|
||||
export const displayDate = new Date(Date.UTC(currentYear, 5, 24));
|
||||
|
||||
export const sampleData = baseData.map(dataItem => (
|
||||
{
|
||||
id: dataItem.TaskID,
|
||||
start: parseAdjust(dataItem.Start),
|
||||
startTimezone: dataItem.startTimezone,
|
||||
end: parseAdjust(dataItem.End),
|
||||
endTimezone: dataItem.endTimezone,
|
||||
isAllDay: dataItem.isAllDay,
|
||||
title: dataItem.Title,
|
||||
description: dataItem.Description,
|
||||
recurrenceRule: dataItem.RecurrenceRule,
|
||||
recurrenceId: dataItem.RecurrenceID,
|
||||
recurrenceExceptions: dataItem.RecurrenceException,
|
||||
|
||||
roomId: dataItem.RoomID,
|
||||
ownerID: dataItem.OwnerID,
|
||||
personId: dataItem.OwnerID
|
||||
}
|
||||
));
|
||||
|
||||
export const sampleDataWithResources = baseData.map(dataItem => (
|
||||
{
|
||||
id: dataItem.TaskID,
|
||||
start: parseAdjust(dataItem.Start),
|
||||
startTimezone: dataItem.startTimezone,
|
||||
end: parseAdjust(dataItem.End),
|
||||
endTimezone: dataItem.endTimezone,
|
||||
isAllDay: dataItem.isAllDay,
|
||||
title: dataItem.Title,
|
||||
description: dataItem.Description,
|
||||
recurrenceRule: dataItem.RecurrenceRule,
|
||||
recurrenceId: dataItem.RecurrenceID,
|
||||
recurrenceExceptions: dataItem.RecurrenceException,
|
||||
roomId: randomInt(1, 2),
|
||||
personId: randomInt(1, 2)
|
||||
}
|
||||
));
|
||||
|
||||
export const sampleDataWithCustomSchema = baseData.map(dataItem => (
|
||||
{
|
||||
...dataItem,
|
||||
Start: parseAdjust(dataItem.Start),
|
||||
End: parseAdjust(dataItem.End),
|
||||
PersonIDs: randomInt(1, 2),
|
||||
RoomID: randomInt(1, 2)
|
||||
}
|
||||
));
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div>
|
||||
<Scheduler
|
||||
:style="{ height: '700px' }"
|
||||
:data-items="sampleData"
|
||||
:default-date="displayDate"
|
||||
:views="views"
|
||||
:slot-render="'slotRender'"
|
||||
>
|
||||
<template v-slot:slotRender="{ props }">
|
||||
<SchedulerSlot
|
||||
v-bind="props"
|
||||
:style="{
|
||||
'background-color':
|
||||
new Date(props.start).toDateString() === new Date().toDateString()
|
||||
? '#56ca85' // Define the color of AllDay slots
|
||||
: undefined,
|
||||
}"
|
||||
@showmoreitems="props.onShowmoreitems"
|
||||
>
|
||||
</SchedulerSlot>
|
||||
</template>
|
||||
</Scheduler>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import '@progress/kendo-date-math/tz/Etc/UTC';
|
||||
import '@progress/kendo-date-math/tz/Europe/Sofia';
|
||||
import { Scheduler, SchedulerSlot } from '@progress/kendo-vue-scheduler';
|
||||
import { sampleData } from './events-utc';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Scheduler,
|
||||
SchedulerSlot,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
views: [
|
||||
{ name: 'week', showWorkHours: false },
|
||||
{ name: 'day' },
|
||||
{ name: 'workWeek' },
|
||||
{ name: 'month' },
|
||||
],
|
||||
sampleData,
|
||||
displayDate: new Date(),
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './main.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,133 @@
|
|||
<template>
|
||||
<div>
|
||||
<h4>Please select a node in the TreeView</h4>
|
||||
<span>Currently selected node: </span>
|
||||
<b>{{ currentPath }}</b>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<TreeView
|
||||
:dataItems="treeDataItems"
|
||||
:expandIcons="true"
|
||||
@expandchange="onExpandChange"
|
||||
:ariaMultiselectable="true"
|
||||
@itemclick="onItemClick"
|
||||
:item="'item'"
|
||||
>
|
||||
<template v-slot:item="{ props }">
|
||||
<span>
|
||||
<span :class="'k-icon k-i-star'" key="0" />
|
||||
{{ props.item.text }}
|
||||
</span>
|
||||
</template>
|
||||
</TreeView>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
TreeView,
|
||||
processTreeViewItems,
|
||||
handleTreeViewCheckChange,
|
||||
} from '@progress/kendo-vue-treeview';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeView,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tree: [
|
||||
{
|
||||
text: 'Furniture',
|
||||
items: [
|
||||
{
|
||||
text: 'Tables & Chairs',
|
||||
},
|
||||
{
|
||||
text: 'Sofas',
|
||||
},
|
||||
{
|
||||
text: 'Occasional Furniture',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Decor',
|
||||
items: [
|
||||
{
|
||||
text: 'Bed Linen',
|
||||
items: [
|
||||
{
|
||||
text: 'Item 1',
|
||||
},
|
||||
{
|
||||
text: 'Item 2',
|
||||
},
|
||||
{
|
||||
text: 'Item 3',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Curtains & Blinds',
|
||||
},
|
||||
{
|
||||
text: 'Carpets',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
expand: {
|
||||
ids: [],
|
||||
idField: 'text',
|
||||
},
|
||||
select: [''],
|
||||
currentPath: 'Node is not selected',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
treeDataItems() {
|
||||
return processTreeViewItems(this.tree, {
|
||||
select: this.select,
|
||||
check: this.check,
|
||||
expand: this.expand,
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getParents(indexArray, index, tree) {
|
||||
if (tree[indexArray[index]]) {
|
||||
if (index + 1 !== indexArray.length) {
|
||||
this.currentPath += tree[indexArray[index]].text + ' > ';
|
||||
} else {
|
||||
this.currentPath += tree[indexArray[index]].text;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < indexArray.length && tree[indexArray[index]].items) {
|
||||
this.getParents(indexArray, index + 1, tree[indexArray[index]].items);
|
||||
}
|
||||
},
|
||||
onItemClick(event) {
|
||||
this.currentPath = '';
|
||||
this.getParents(
|
||||
event.itemHierarchicalIndex.split('_').map(Number),
|
||||
0,
|
||||
this.tree
|
||||
);
|
||||
this.select = [event.itemHierarchicalIndex];
|
||||
},
|
||||
onExpandChange(event) {
|
||||
let ids = this.expand.ids.slice();
|
||||
const index = ids.indexOf(event.item.text);
|
||||
index === -1 ? ids.push(event.item.text) : ids.splice(index, 1);
|
||||
this.expand = {
|
||||
ids,
|
||||
idField: 'text',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Add an Popup Action Button to a Grid Row
|
||||
description: An example on how to add a custom Action button that controls the state of the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Add an Action Button to a Grid Row - Kendo UI for Vue Native Grid
|
||||
slug: grid-add-action-button-with-popup
|
||||
tags: grid, action, button, popup, kendovue, row, style, color
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.4.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base article shows how we can add an action button to the rows of the Native Grid component. Using this action button, we can control the data state of the Grid or change the look of the component.
|
||||
|
||||
## Solution
|
||||
|
||||
The way we define the action button in the Grid column is through the [`cell`](slug:api_grid_gridcolumnprops#toc-cell) column property. The custom template passed to this property is defined as follows:
|
||||
|
||||
``` js
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :data-item="props.dataItem"
|
||||
@actionselect="actionSelected"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
The definition of the `custom` component can be seen in the `ActionCell.vue` file in the below example.
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:560 %}
|
||||
{% embed_file grid-add-action-button-with-popup/main.vue preview %}
|
||||
{% embed_file grid-add-action-button-with-popup/ActionCell.vue %}
|
||||
{% embed_file grid-add-action-button-with-popup/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
title: Add Multiple Rows to the Native Grid's Footer and Display Aggregates and Custom Data
|
||||
description: An example demonstrating how to display multiple footer rows in the Kendo UI for Vue Native Grid and display different custom data-like aggregates.
|
||||
type: how-to
|
||||
page_title: Add a Multi-Row Footer with Custom Data in the Native Grid - Kendo UI for Vue Native Grid
|
||||
slug: grid-add-multi-row-footer
|
||||
tags: grid, footer, custom footer, multirow, multiple, rows, aggregates,custom data, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.3.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base article shows how you can add a multi-row footer to the Native `Grid` and display custom data(like aggregates or other) in each of the rows.
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
The below solution uses the [footerCell](slug:api_grid_gridcolumnprops#toc-footercell) property of the Native Grid's column. By passing custom slot templates with similar structures to the `footerCell` props of each column, we can create a multi-row footer for the whole Grid component.
|
||||
|
||||
To achieve the targeted functionality we have the following templates for the footers of each of the three columns in our Grid:
|
||||
|
||||
**Footer template of the Product ID column**
|
||||
```js
|
||||
<template v-slot:footerTemplate1="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span> </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
**Footer template of the Product Name column**
|
||||
```js
|
||||
<template v-slot:footerTemplate2="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span>Custom Footer Row 1</span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span @click="customHandler">Custom Footer Row 2</span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span @click="customHandler">Column field: {{ props.field }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
**Footer template of the Unit Price column**
|
||||
```js
|
||||
<template v-slot:footerTemplate3="{ props }">
|
||||
<div>
|
||||
<div class="first-footer-row">
|
||||
<span>The sum</span>
|
||||
</div>
|
||||
<div class="second-footer-row">
|
||||
<span>of the above rows is:</span>
|
||||
</div>
|
||||
<div style="padding: 2px">
|
||||
<span @click="customHandler"> {{ unitPriceSum }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
Each of the above templates are passed to the columns configuration of the Grid though the following object:
|
||||
```js
|
||||
columns: [
|
||||
{ field: 'ProductID', footerCell: 'footerTemplate1' },
|
||||
{
|
||||
field: 'ProductName',
|
||||
title: 'Product Name',
|
||||
footerCell: 'footerTemplate2',
|
||||
},
|
||||
{
|
||||
field: 'UnitPrice',
|
||||
title: 'Unit Price',
|
||||
footerCell: 'footerTemplate3',
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:400 %}
|
||||
{% embed_file grid-add-multi-row-footer/main.vue preview %}
|
||||
{% embed_file grid-add-multi-row-footer/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
title: Define a Grid Custom Cell Template with Grouping and Selection
|
||||
description: An example on how to define a custom cell template that keeps the grouping and rows' selection functionality in the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Implement a Grid Cell Template with Grouping and Selection - Kendo UI for Vue Native Grid
|
||||
slug: grid-custom-cell-grouping-and-selection
|
||||
tags: grid, rows, group, selection, kendovue
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.0.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The below example demonstrates how we can keep the Grouping and Select functionality of the Grid while using a custom cell template inside the Kendo UI for Vue Native Grid
|
||||
|
||||
## Solution
|
||||
|
||||
To define a custom template, use the Use a [`cellRender`](slug:api_grid_gridprops#toc-cellrender) prop of the Native Grid. Initialize the `CustomCell` component inside the slot template that is passed to the `cellRender` as demonstrated below:
|
||||
|
||||
```js
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :field="props.field"
|
||||
:expanded="props.expanded"
|
||||
:row-type="props.rowType"
|
||||
:level="props.level"
|
||||
:column-index="props.columnIndex"
|
||||
:columns-count="props.columnsCount"
|
||||
:data-item="props.dataItem"
|
||||
:class-name="props.className"
|
||||
@selectionchange="selectionChange"
|
||||
@click="clickHandler(props.dataItem)" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:580 %}
|
||||
{% embed_file grid-custom-cell-grouping-and-selection/main.vue preview %}
|
||||
{% embed_file grid-custom-cell-grouping-and-selection/CustomCell.vue %}
|
||||
{% embed_file grid-custom-cell-grouping-and-selection/main.js %}
|
||||
{% embed_file shared/products.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
title: Modify the Date Format in the Grid
|
||||
description: An example on how to format ISO string dates in the Kendo UI for Vue Data Grid.
|
||||
type: how-to
|
||||
page_title: Change the Date Format - Kendo UI for Vue Data Grid
|
||||
slug: grid-date-format
|
||||
tags: grid, kendovue, dates, format
|
||||
ticketid: 1402874
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.2.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
How can I change an ISO date string which I have in my Kendo UI for Vue Data Grid? Setting a [`format`](slug:api_grid_gridcolumnprops#toc-format) property does not affect the current date format.
|
||||
|
||||
## Solution
|
||||
|
||||
In such case we can use the [`type`](slug:api_grid_gridcolumnprops#toc-type) property and set the correct type of the data that is expected from the server.
|
||||
|
||||
{% meta height:380 %}
|
||||
{% embed_file grid-date-format/main.vue preview %}
|
||||
{% embed_file grid-date-format/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
title: Add a Native Grid with a Custom Template, Row Details, and Grouping
|
||||
description: An example on how to combine grouping, row details, and custom templates in the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Add a Grid with Grouping, Row Details, and Custom Template - Kendo UI for Vue Native Grid
|
||||
slug: grid-details-template-with-grouping
|
||||
tags: grid, details, custom, template, group, grouping, kendovue
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.4.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base article demonstrates how the Grouping, row Details and custom template functionality of the Native Grid can be combined.
|
||||
|
||||
## Solution
|
||||
|
||||
The Details template of the Grid can be defined with the [`detail`](slug:api_grid_gridprops#toc-detail) property. The template passed to this property in the below example is defined as follows:
|
||||
|
||||
``` js
|
||||
<template v-slot:cellDetailTemplate="{props}">
|
||||
<section>
|
||||
<p><strong>Descriptions:</strong> {{props.dataItem.ProductName}}</p>
|
||||
</section>
|
||||
</template>
|
||||
```
|
||||
|
||||
The custom template in which the Grouping functionality is implemented is passed to the Grid through its [`cellRender`](slug:api_grid_gridprops#toc-cellrender) property. The slot template passed to the `cellRender` is the following one:
|
||||
|
||||
``` js
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :field="props.field"
|
||||
:expanded="props.expanded"
|
||||
:row-type="props.rowType"
|
||||
:level="props.level"
|
||||
:column-index="props.columnIndex"
|
||||
:columns-count="props.columnsCount"
|
||||
:data-item="props.dataItem"
|
||||
:class-name="props.className"
|
||||
@click="clickHandler(props.dataItem)" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:600 %}
|
||||
{% embed_file grid-details-template-with-grouping/main.vue preview %}
|
||||
{% embed_file grid-details-template-with-grouping/CustomCell.vue %}
|
||||
{% embed_file grid-details-template-with-grouping/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
title: Display and Edit Multiple Data Item Fields in a Single Native Grid Cell
|
||||
description: An example on how to display and edit multiple data item fields in one Kendo UI for Vue Native Grid cell.
|
||||
type: how-to
|
||||
page_title: Show and Edit Multiple Data Item Fields in One Grid Cell - Kendo UI for Vue Native Grid
|
||||
slug: grid-display-and-edit-multiple-dataitem-fields-in-one-cell
|
||||
tags: grid, custom cell, show, display, edit, multiple fields, single cell, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.3.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The current Knowledge base article demonstrates how you can display multiple data item fields data in a single Kendo UI for Vue Native `Grid` cell.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
The below solution uses the [cell](slug:api_grid_gridcolumnprops#toc-cell) property of the Native Grid's column. Through this property, we can customize the way the selected cell looks.
|
||||
|
||||
To display the `Status`, `Public`, and `Hide` fields available in the data item of each Grid row, the example uses the `StatusCell` custom component. What the custom component does is ensure the displaying of more than one data item in the "Status" field of the Grid.
|
||||
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:500 %}
|
||||
{% embed_file grid-display-and-edit-multiple-dataitem-fields-in-one-cell/main.vue preview %}
|
||||
{% embed_file grid-display-and-edit-multiple-dataitem-fields-in-one-cell/main.js %}
|
||||
{% embed_file grid-display-and-edit-multiple-dataitem-fields-in-one-cell/CommandCell.vue %}
|
||||
{% embed_file grid-display-and-edit-multiple-dataitem-fields-in-one-cell/StatusCell.vue %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: Drag and Drop Rows between Two Grids
|
||||
description: An example of how to move records from one Kendo UI for Vue Native Grid to another.
|
||||
type: how-to
|
||||
page_title: Drag and Drop Rows between Two Grids - Kendo UI for Vue Native Grid
|
||||
slug: grid-drag-and-drop-rows-between-two-grids
|
||||
tags: grid, rows, drag, drop, reorder, kendovue
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.4.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The current Knowledge base article shows how we can drag and drop rows between two Kendo UI for Vue Native Grids.
|
||||
|
||||
## Solution
|
||||
|
||||
To define the Draggable functionality of the Grids' rows, the below slot template is defined and passed to the "Drag" field in each of the Grids.
|
||||
|
||||
```js
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :data-item="props.dataItem"
|
||||
@dragover="reorder"
|
||||
@dragstart="setActive"
|
||||
@dragend="updateRemote"/>
|
||||
</template>
|
||||
```
|
||||
Once the `reorder` function from the above template is triggered, it applies the changes in the states of the two Grids.
|
||||
|
||||
For more information about the rows reordering in the Kendo UI for Vue Native Grid, you can check [this documentation article](slug:rowreorder_grid).
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:580 %}
|
||||
{% embed_file grid-drag-and-drop-rows-between-two-grids/main.vue preview %}
|
||||
{% embed_file grid-drag-and-drop-rows-between-two-grids/CustomCell.vue %}
|
||||
{% embed_file grid-drag-and-drop-rows-between-two-grids/main.js %}
|
||||
{% embed_file shared/products.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
title: Edit the Grid's Header on Double-Click
|
||||
description: An example demonstrating how to edit the headers of the kendo UI for Vue Native Grid on double-click.
|
||||
type: how-to
|
||||
page_title: Edit Native Grid's Headers on Double-Click - Kendo UI for Vue Native Grid
|
||||
slug: grid-edit-column-headers-on-double-click
|
||||
tags: grid, data grid, column header, edit, double click, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.3.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The below example implements a logic that allows you to edit the column headers of the Native Grid when double-clicking on each of them.
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To be able to edit the Grid's headers on the fly, we have to use the [headerCell](slug:api_grid_gridcolumnprops#toc-headercell) property of the `Native Grid's` columns and define a custom header for each column. The below example uses the following template that is passed to the `headerCell` prop of all column.
|
||||
|
||||
```js
|
||||
<template v-slot:headerTemplate="{ props }">
|
||||
<span
|
||||
v-if="!getColumnItem(props).headerInEdit"
|
||||
@dblclick="(e) => customHandler(e, props)"
|
||||
>{{ props.title }}</span
|
||||
>
|
||||
<span v-else
|
||||
><k-input
|
||||
@blur="onBlur(props)"
|
||||
@input="(e) => onInput(e, props)"
|
||||
type="text"
|
||||
:value="props.title"
|
||||
/></span>
|
||||
</template>
|
||||
```
|
||||
With the above, the default behavior of the header will be to show the current value of its title(defined in the `columns` array). Then if we double-click on a random header, it will enter in **edit** mode by which you can change the `title` value.
|
||||
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:460 %}
|
||||
{% embed_file grid-edit-column-headers-on-double-click/main.vue preview %}
|
||||
{% embed_file grid-edit-column-headers-on-double-click/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
title: Export to Excel the data of a Grid that has a defined detail-row template.
|
||||
description: A a sample project that shows how to export to Excel the data of a Kendo UI for Vue Native Grid with a detail-row template.
|
||||
type: how-to
|
||||
page_title: Export to Excel the data of a Grid with a defined detail-row template
|
||||
slug: grid-export-to-excel-grid-with-detail-row-template
|
||||
tags: grid, export, excel, detail template, detail-row, row, template, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article shows how you can export to Excel the data from a Kendo UI for Vue Native Data Grid that has a defined detail-row template.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To export the Grids' data we need the following imports:
|
||||
* `saveAs` method available in the **@progress/kendo-file-saver** package
|
||||
* `workbookOptions` and `toDataURL` methods available in the **@progress/kendo-vue-excel-export** package
|
||||
|
||||
To export the data of the Grid we call the following method and pass to it the `data` and the `columns` definition:
|
||||
|
||||
```js-no-run
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
```
|
||||
|
||||
The above calls the the `customSaveExcel` method in which we have these lines:
|
||||
```js-no-run
|
||||
const options = workbookOptions(exportOptions);
|
||||
const rows = options.sheets[0].rows;
|
||||
```
|
||||
The `rows` variable is an array that holds the rows data of the main Grid that has a retail-row template definition. To export the data of the sub-Grids below each detail row, we have to manually get the data and insert it in the `rows` array.
|
||||
|
||||
To add the data of the Grids in the detailed rows of the main Grid we use the following code.
|
||||
|
||||
```js-no-run
|
||||
this.categories.forEach((category) => {
|
||||
currentCategoryProducts = this.products.filter(
|
||||
(item) => item.CategoryID === category.CategoryID
|
||||
);
|
||||
rows.find((el, index) => {
|
||||
if (el.cells[0].value === currentCategoryProducts[0].CategoryID) {
|
||||
currentRowIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
// Add the Detail tables' data
|
||||
for (
|
||||
let productIdx = currentCategoryProducts.length - 1;
|
||||
productIdx >= 0;
|
||||
productIdx--
|
||||
) {
|
||||
const product = currentCategoryProducts[productIdx];
|
||||
rows.splice(currentRowIndex + 1, 0, {
|
||||
cells: [
|
||||
{},
|
||||
{ value: product.ProductID },
|
||||
{ value: product.ProductName },
|
||||
{ value: product.UnitPrice },
|
||||
{ value: product.UnitsInStock },
|
||||
],
|
||||
}); // Add all products of the current category
|
||||
}
|
||||
|
||||
// Apply color to the headers of the Detail tables
|
||||
rows.splice(currentRowIndex + 1, 0, {
|
||||
cells: [
|
||||
{},
|
||||
Object.assign({}, headerOptions, { value: 'Product ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Product Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'Unit Price' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units In Stock' }),
|
||||
],
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The actual export of the Grids' data is done by this line:
|
||||
|
||||
```js-no-run
|
||||
toDataURL(options).then(saveFn);
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:620 %}
|
||||
{% embed_file grid-export-to-excel-grid-with-detail-row-template/main.vue preview %}
|
||||
{% embed_file grid-export-to-excel-grid-with-detail-row-template/DetailComponent.vue preview %}
|
||||
{% embed_file grid-export-to-excel-grid-with-detail-row-template/main.js %}
|
||||
{% embed_file grid-export-to-excel-grid-with-detail-row-template/products.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
title: Export to Excel the Data from two separate Native Grids and save it in two separate sheets of the exported file.
|
||||
description: A a sample project that shows how to export to Excel the data from two Kendo UI for Vue Native Grids and put this data in two separate sheets.
|
||||
type: how-to
|
||||
page_title: Export to Excel two Data Grids and put this data in two separate sheets | Kendo UI for Vue Native Grid
|
||||
slug: grid-export-two-grids-to-one-excel-file-different-sheets
|
||||
tags: grid, export, excel, two sheets, separate, sheets two grids, two, grids, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article shows how you can export the data from two Kendo UI for Vue Native Data Grids to Excel. The data in the current KB is saved in two separate sheets of the exported file.
|
||||
|
||||
If you need to export the two Grids' data to one sheet, you can check this [Export to Excel the Data from two separate Native Grids and save it in one sheet of the exported file]({% slug grid-export-two-grids-to-one-excel-file-same-sheet %}).
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To export the Grids' data we need the following imports:
|
||||
* `saveAs` method available in the **@progress/kendo-file-saver** package
|
||||
* `workbookOptions` and `toDataURL` methods available in the **@progress/kendo-vue-excel-export** package
|
||||
|
||||
To export the data of the Grids we call the following method and pass to it the `data` and the `columns` definitions of the first Grid:
|
||||
|
||||
```js-no-run
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
```
|
||||
|
||||
The above calls the the `customSaveExcel` method in which we have these lines:
|
||||
```js-no-run
|
||||
const options = workbookOptions(exportOptions);
|
||||
const headerOptions = options.sheets[0].rows[0].cells[0];
|
||||
options.sheets.push({ rows: [] });
|
||||
const rows = options.sheets[1].rows;
|
||||
```
|
||||
The third line above adds a new sheet to the exported Excel file. The `rows` variable is and empty array in which we will add data of the second Grid. To add the records of the second Grid to the second sheet of the exported Excel we use the following code. The first `push` below adds the header of the second Grid and the `forEach` loop adds its data.
|
||||
|
||||
```js-no-run
|
||||
rows.push({
|
||||
cells: [
|
||||
Object.assign({}, headerOptions, { value: 'ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'First Ordered' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units' }),
|
||||
Object.assign({}, headerOptions, { value: 'Discontinued' }),
|
||||
],
|
||||
});
|
||||
this.grid2Data.forEach((category) => {
|
||||
rows.push({
|
||||
cells: [
|
||||
{ value: category.ProductID },
|
||||
{ value: category.ProductName },
|
||||
{ value: category.FirstOrderedOn },
|
||||
{ value: category.UnitsInStock },
|
||||
{ value: category.Discontinued },
|
||||
],
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The actual export of the Grids' data is done by this line:
|
||||
|
||||
```js-no-run
|
||||
toDataURL(options).then(saveFn);
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:950 %}
|
||||
{% embed_file grid-export-two-grids-to-one-excel-file-different-sheets/main.vue preview %}
|
||||
{% embed_file grid-export-two-grids-to-one-excel-file-different-sheets/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
title: Export to Excel the Data from two separate Native Grids and save it in one sheet of the exported file.
|
||||
description: A a sample project that shows how to export to Excel the data from two Kendo UI for Vue Native Grids and put this data in one sheet.
|
||||
type: how-to
|
||||
page_title: Export to Excel two Data Grids and put this data in one sheet | Kendo UI for Vue Native Grid
|
||||
slug: grid-export-two-grids-to-one-excel-file-same-sheet
|
||||
tags: grid, export, excel, one sheet, two grids, two, grids, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article shows how you can export the data from two Kendo UI for Vue Native Data Grids to Excel. The data in the current KB is saved in one sheet of the exported file.
|
||||
|
||||
If you need to export the two Grids' data to separate sheets, you can check this [Export to Excel the Data from two separate Native Grids and save it to different sheets of the exported file]({% slug grid-export-two-grids-to-one-excel-file-different-sheets %}).
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To export the Grids' data we need the following imports:
|
||||
* `saveAs` method available in the **@progress/kendo-file-saver** package
|
||||
* `workbookOptions` and `toDataURL` methods available in the **@progress/kendo-vue-excel-export** package
|
||||
|
||||
To export the data of the Grids we call the following method and pass to it the `data` and the `columns` definitions of the first Grid:
|
||||
|
||||
```js-no-run
|
||||
exportExcel() {
|
||||
this.customSaveExcel({
|
||||
data: this.categories,
|
||||
fileName: 'myFile',
|
||||
columns: this.columns,
|
||||
});
|
||||
},
|
||||
```
|
||||
|
||||
The above calls the the `customSaveExcel` method in which we have these lines:
|
||||
```js-no-run
|
||||
const options = workbookOptions(exportOptions);
|
||||
const rows = options.sheets[0].rows;
|
||||
```
|
||||
The `rows` variable is an array that holds the data of the first Grid in a format that can be exported to Excel. To add the records of the second Grid to the exported Excel, we need to manually insert its data in the `rows` array. The first `push` below adds the header of the second Grid and the `forEach` loop adds its data.
|
||||
|
||||
```js-no-run
|
||||
rows.push({
|
||||
cells: [
|
||||
Object.assign({}, headerOptions, { value: 'ID' }),
|
||||
Object.assign({}, headerOptions, { value: 'Name' }),
|
||||
Object.assign({}, headerOptions, { value: 'First Ordered' }),
|
||||
Object.assign({}, headerOptions, { value: 'Units' }),
|
||||
Object.assign({}, headerOptions, { value: 'Discontinued' }),
|
||||
],
|
||||
});
|
||||
this.grid2Data.forEach((category) => {
|
||||
rows.push({
|
||||
cells: [
|
||||
{ value: category.ProductID },
|
||||
{ value: category.ProductName },
|
||||
{ value: category.FirstOrderedOn },
|
||||
{ value: category.UnitsInStock },
|
||||
{ value: category.Discontinued },
|
||||
],
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The actual export of the Grids' data is done by this line:
|
||||
|
||||
```js-no-run
|
||||
toDataURL(options).then(saveFn);
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:950 %}
|
||||
{% embed_file grid-export-two-grids-to-one-excel-file-same-sheet/main.vue preview %}
|
||||
{% embed_file grid-export-two-grids-to-one-excel-file-same-sheet/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,120 @@
|
|||
---
|
||||
title: Implement Multifunctional Native Grid with Grouping, Detail Template, Localization, Sorting, PDF and Excel Export
|
||||
description: An example of how to implement a complex Native Grid scenario that covers most of the widely used options of the Kendo UI for Vue Native Grid component.
|
||||
type: how-to
|
||||
page_title: Implement a Multifunctional Native Grid - Kendo UI for Vue Native Grid
|
||||
slug: grid-grouping-detail-template-localization-sortable-reorderable
|
||||
tags: grid, grouping, detail template, localization, sorting, column lock, pdf export, excel export, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.0.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base article shows how we can implement some of the most widely used Native Grid functionalities:
|
||||
* Data Grouping
|
||||
* Detail Template for each row
|
||||
* Localization & Globalization of the component
|
||||
* Data sorting
|
||||
* Column reordering
|
||||
* Column locking
|
||||
* Excel export
|
||||
* PDF export
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
**Data grouping configuration**
|
||||
|
||||
To make the Grid data groupable:
|
||||
1. First thing that should be done is to set the [groupable property](slug:api_grid_gridprops#toc-groupable) to `true`.
|
||||
2. To have a grouped data, by default, set a value for the [group property](slug:api_grid_gridprops#toc-group). In the below example the value of the `group` property is:
|
||||
```js
|
||||
group: [
|
||||
{ field: 'customerID' }
|
||||
],
|
||||
```
|
||||
The above will initially group Grid's data by the `customerID` column.
|
||||
|
||||
**Detail Template configuration**
|
||||
|
||||
To define a detail template use the [detail property](slug:api_grid_gridprops#toc-detail). Pass a slot template to this property. Inside the slot template, you can use a custom template that formats the detail row data. The detail slot template used in the below example is defined as follows.
|
||||
```js
|
||||
<template v-slot:myTemplate="{props}">
|
||||
<custom :data-item="props.dataItem" />
|
||||
</template>
|
||||
```
|
||||
**Localization & Globalization**
|
||||
|
||||
The Localization & Globalization of the component are achieved with the `IntlProvider`, `load`, `LocalizationProvider`, `loadMessages`, `IntlService` components and methods that are part of the `@progress/kendo-vue-intl` package.
|
||||
More details you can find on [Grid's Globalization page](slug:globalization_grid).
|
||||
|
||||
**Data Sorting**
|
||||
|
||||
To make the Grid data sortable:
|
||||
1. Set the [sortable property](slug:api_grid_gridprops#toc-sortable) to `true`.
|
||||
2. To have a sorted data, by default, set a value for the [sort property](slug:api_grid_gridprops#toc-sort). In the below example the value of the `sort` property is:
|
||||
```js
|
||||
sort: [
|
||||
{ field: 'orderDate', dir: 'desc' }
|
||||
]
|
||||
```
|
||||
The above will initially sort Grid's data by the `orderDate` column, in descending order.
|
||||
|
||||
**Column reordering**
|
||||
|
||||
To make Grid columns reorderable, set the [reorderable property](slug:api_grid_gridprops#toc-reorderable) to true.
|
||||
|
||||
**Column locking**
|
||||
|
||||
To lock a given column in the Grid, add the [locked column prop](slug:api_grid_gridcolumnprops#toc-locked) to its definition and set its value to `true`.
|
||||
|
||||
**Excel export**
|
||||
|
||||
The Excel export functionality of the data Grid is based on the `saveExcel` method that is part of the `@progress/kendo-vue-excel-export` package.
|
||||
More about the Export excel functionality shipped with the Kendo UI for Vue suite, you can find in our [Excel Export documentation](slug:overview_excelexport_vue).
|
||||
|
||||
**PDF export**
|
||||
The PDF export in the below example is implemented with the `GridPdfExport` component that is part of the `@progress/kendo-vue-pdf` package.
|
||||
The content that is exported to a PDF file is wrapped in the `pdfexport` tag inside the template section of the `main.vue` file. Using the below code, the content wrapped in the `pdfexport` tag will be exported in the PDF file. More details about the [Grid PDF Export documentation](slug:overview_pdfexport_grid).
|
||||
|
||||
```js
|
||||
exportPDF () {
|
||||
const tempSort = this.sort;
|
||||
this.sort = null;
|
||||
this.$nextTick(()=>{
|
||||
(this.$refs.gridPdfExport).save(process(orders,
|
||||
{ skip: this.skip, take: this.take }));
|
||||
this.sort = tempSort;
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:760 %}
|
||||
{% embed_file grid-grouping-detail-template-localization-sortable-reorderable/main.vue preview %}
|
||||
{% embed_file grid-grouping-detail-template-localization-sortable-reorderable/DetailComponent.vue %}
|
||||
{% embed_file grid-grouping-detail-template-localization-sortable-reorderable/main.js %}
|
||||
{% embed_file grid-grouping-detail-template-localization-sortable-reorderable/orders.json %}
|
||||
{% embed_file grid-grouping-detail-template-localization-sortable-reorderable/es.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
title: Customize the template/content of a locked Native Grid column using a cell template.
|
||||
description: A project demonstrating how we can customize the content of a locked Native Grid column by defining a custom cell template.
|
||||
type: how-to
|
||||
page_title: Learn how to implement a locked column with a custom cell template inside the Native Grid
|
||||
slug: grid-locked-column-with-custom-template
|
||||
tags: grid, locked, column, custom, template, cell, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article demonstrates how we can customize the template of a specific `locked` Native Grid column by defining a `custom cell template`.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
The current example demonstrates how we can **bold** the content of the `ProductID` and `Discontinued` columns in the Kendo UI for Vue Native Grid. Both the `ProductID` and `Discontinued` columns are defined as locked and to be able to customize their content, we need to use a template as follows:
|
||||
|
||||
```js-no-run
|
||||
<template v-slot:myLockedCell="{ props }">
|
||||
<td
|
||||
:colspan="props.colspan"
|
||||
:class="props.class"
|
||||
:role="props.role"
|
||||
:data-grid-col-index="props['data-grid-col-index']"
|
||||
:aria-selected="props['aria-selected']"
|
||||
>
|
||||
<b>{{ props.dataItem[props.field] }}</b>
|
||||
</td>
|
||||
</template>
|
||||
```
|
||||
|
||||
Once we have the above template defined, what we need to do is to pass its name(`myLockedCell`) to the [cell]({% slug api_grid_gridcolumnprops %}#toc-cell) column property. To do this, we are using the following definition:
|
||||
```js-no-run
|
||||
columns: [
|
||||
{
|
||||
field: 'ProductID',
|
||||
title: 'ID',
|
||||
width: '45px',
|
||||
cell: 'myLockedCell',
|
||||
locked: true,
|
||||
},
|
||||
.........
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:480 %}
|
||||
{% embed_file grid-locked-column-with-custom-template/main.vue preview %}
|
||||
{% embed_file grid-locked-column-with-custom-template/products.js %}
|
||||
{% embed_file grid-locked-column-with-custom-template/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
title: Add Styles to Dragged Rows in the Native Grid
|
||||
description: An example on how to style the currently dragged row when reordering rows in the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Style the Dragged Row - Kendo UI for Vue Native Grid
|
||||
slug: grid-style-dragged-row-on-row-reorder
|
||||
tags: grid, rows, reorder, drag, kendovue, style
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.4.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
The current Knowledge base article demonstrates how we can add style to the row that is currently dragged inside the Native Grid component. With this styling, the users can easily identify which row is currently dragged and which will be its position when dropped.
|
||||
|
||||
## Solution
|
||||
|
||||
To add style to the currently dragged row inside the Native Grid, we can use its built-in style for `selected` field. To use this functionality, in the setActive method in the example we set the `selected` field of the currently active row to `true`.
|
||||
|
||||
```js
|
||||
setActive(dataItem) {
|
||||
this.activeItem = dataItem;
|
||||
this.activeItem.selected = true;
|
||||
}
|
||||
```
|
||||
|
||||
To reset the style of a row, once it is dropped, the below code is used.
|
||||
```js
|
||||
this.items = this.items.map(i => {
|
||||
i.selected = undefined;
|
||||
return i;
|
||||
})
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:480 %}
|
||||
{% embed_file grid-style-dragged-row-on-row-reorder/main.vue preview %}
|
||||
{% embed_file grid-style-dragged-row-on-row-reorder/CustomCell.vue %}
|
||||
{% embed_file grid-style-dragged-row-on-row-reorder/main.js %}
|
||||
{% embed_file shared/products.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
title: Style the filtered columns in the Kendo UI for Vue Native Grid.
|
||||
description: A project demonstrating how to add a custom style that will visually differentiate the filtered Native Grid columns from the unfiltered ones.
|
||||
type: how-to
|
||||
page_title: See how you can apply a custom style to the filtered Grid columns and thus differentiate them from the unfiltered ones.
|
||||
slug: grid-style-filtered-columns
|
||||
tags: grid, style, filtered, column, custom, template, header, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article demonstrates how we can customize the template of a specific `locked` Native Grid column by defining a `custom cell template`.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
This Knowledge Base(KB) article shows how you can apply a custom CSS style to the headers of the filtered columns inside the Native Grid. To achieve the desired scenario, the Grid columns are defined as a computed property as follows:
|
||||
```js-no-run
|
||||
columns: function () {
|
||||
const columns = [
|
||||
{
|
||||
field: 'ProductID',
|
||||
filterable: false,
|
||||
title: 'Product ID',
|
||||
width: '50px',
|
||||
},
|
||||
{ field: 'ProductName', title: 'Product Name' },
|
||||
{ field: 'FirstOrderedOn', filter: 'date', title: 'First Ordered On' },
|
||||
{ field: 'UnitPrice', filter: 'numeric', title: 'Unit Price' },
|
||||
{ field: 'Discontinued', filter: 'boolean', title: 'Discontinued' },
|
||||
].map((col) => {
|
||||
return this.isFiltered(col)
|
||||
? {
|
||||
...col,
|
||||
headerClassName: 'filtered',
|
||||
}
|
||||
: col;
|
||||
});
|
||||
return columns;
|
||||
}
|
||||
```
|
||||
|
||||
The above definition adds the `filtered` CSS class to the header of the filtered columns, based on the result of the following `isFiltered` method:
|
||||
```js-no-run
|
||||
isFiltered(col) {
|
||||
const filters = this.filter ? this.filter.filters : [];
|
||||
return filters.findIndex((f) => f.field === col.field) >= 0;
|
||||
}
|
||||
```
|
||||
|
||||
The styles that will be applied to the Grid's header are defined in the following class:
|
||||
```css
|
||||
.filtered {
|
||||
background-color: red;
|
||||
}
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta height:480 %}
|
||||
{% embed_file grid-style-filtered-columns/main.vue preview %}
|
||||
{% embed_file grid-style-filtered-columns/products.js %}
|
||||
{% embed_file grid-style-filtered-columns/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
title: Merge Rows in the Grid
|
||||
description: An example on how to merge rows in the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Merge Rows in the Grid - Kendo UI for Vue Native Grid
|
||||
slug: merge-row-in-the-grid
|
||||
tags: grid, rows, merge, kendovue
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.3.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
How can I merge rows in the Kendo UI for Vue Native Grid?
|
||||
|
||||
## Solution
|
||||
|
||||
Use a [`cellRender`](slug:api_grid_gridprops#toc-cellrender) and add `rowSpan` to the cells that need it.
|
||||
|
||||
{% meta id:index height:760 %}
|
||||
{% embed_file merge-rows-in-grid/main.vue preview %}
|
||||
{% embed_file merge-rows-in-grid/main.js preview %}
|
||||
{% embed_file shared/products.json %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
title: Display HTML in the Native Grid
|
||||
description: An example of how to render HTML in the Kendo UI for Vue Native Grid.
|
||||
type: how-to
|
||||
page_title: Render HTML in the Grid - Kendo UI for Vue Native Grid
|
||||
slug: render-html-in-native-grid
|
||||
tags: grid, render, html, style
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2.4.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
How can I render HTML inside the Kendo UI for Vue Native Grid?
|
||||
|
||||
## Solution
|
||||
|
||||
Define a custom template for the Grid column that should display rendered HTML. Pass the custom template to the selected column using the cell [`cell`](slug:api_grid_gridcolumnprops#toc-cell) column property. Define the custom template as follows:
|
||||
|
||||
``` js
|
||||
<template v-slot:myTemplate="{props, listeners}">
|
||||
<td :class="props.className" v-html="getNestedValue(props.field, props.dataItem)"></td>
|
||||
</template>
|
||||
```
|
||||
|
||||
Add apply the template to the selected column with the following definition:
|
||||
|
||||
``` js
|
||||
{ field: 'ProductName', title: 'Product Name', cell: 'myTemplate' }
|
||||
```
|
||||
|
||||
{% meta id:index height:360 %}
|
||||
{% embed_file render-html-in-native-grid/main.vue preview %}
|
||||
{% embed_file render-html-in-native-grid/main.js preview %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: Highlight the 'today' slot in each Native Scheduler view.
|
||||
description: A sample project that demonstrates how define a custom template to highlight the today's slot in each Native Scheduler View.
|
||||
type: how-to
|
||||
page_title: Learn how to customize the Native Scheduler's Slot template to highlight the today's slot in each View.
|
||||
slug: scheduler-highlight-today-date-in-all-views
|
||||
tags: scheduler, slot, template, custom, today, highlight, color, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article shows how you can display the list of the parent nodes above the selected TreeView node. With the demonstrated approach you can get the 'path' from the root of the TreeView to the selected node.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
### Define the custom template
|
||||
|
||||
To highlight the current date in all Native Scheduler Views, we need to customize its slot. The desired functionality can be achieved using the following custom `Slot template`.
|
||||
|
||||
```js-no-run
|
||||
<template v-slot:slotRender="{ props }">
|
||||
<SchedulerSlot
|
||||
v-bind="props"
|
||||
:style="{
|
||||
'background-color':
|
||||
new Date(props.start).toDateString() === new Date().toDateString()
|
||||
? '#56ca85' // Define the color of AllDay slots
|
||||
: undefined,
|
||||
}"
|
||||
@showmoreitems="props.onShowmoreitems"
|
||||
>
|
||||
</SchedulerSlot>
|
||||
</template>
|
||||
```
|
||||
> More details about the custom Slot templates you can find [on this Scheduler Custom Slot template documentation article]({% slug scheduler_custom_slot %}).
|
||||
|
||||
### Pass the template to the Scheduler
|
||||
|
||||
To apply the above `slotRender` template is we have to pass it to the [slotRender]({% slug api_scheduler_schedulerprops %}#toc-slotrender) property of the Native Scheduler.
|
||||
```
|
||||
:slot-render="'slotRender'"
|
||||
```
|
||||
### The result
|
||||
|
||||
By applying the shared above implementation the `today`'s cell in all Native Scheduler views will have a background with the **#56ca85** color.
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:800 %}
|
||||
{% embed_file scheduler-highlight-today-date-in-all-views/main.vue preview %}
|
||||
{% embed_file scheduler-highlight-today-date-in-all-views/events-utc.js %}
|
||||
{% embed_file scheduler-highlight-today-date-in-all-views/main.js %}
|
||||
{% endmeta %}
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
title: Show the list of the parent nodes of a selected TreeView node.
|
||||
description: A sample project that shows how to list the parent nodes of a selected TreeView node.
|
||||
type: how-to
|
||||
page_title: Learn how to display the parent nodes(path) of a selected TreeView node.
|
||||
slug: treeview-show-parent-nodes-path
|
||||
tags: treeview, path, parent, nodes, selected, kendovue, native
|
||||
res_type: kb
|
||||
category: knowledge-base
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>3.6.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Progress® Kendo UI for Vue Native</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This Knowledge base(KB) article shows how you can display the list of the parent nodes above the selected TreeView node. With the demonstrated approach you can get the 'path' from the root of the TreeView to the selected node.
|
||||
|
||||
|
||||
**KB sections**
|
||||
|
||||
* [Solution description](#toc-solution-description)
|
||||
* [Runnable example](#toc-runnable-example)
|
||||
|
||||
## Solution description
|
||||
|
||||
To get the `path` from the root element to the select node we are using the following method which is called every time a TreeView node is selected.
|
||||
|
||||
```js-no-run
|
||||
getParents(indexArray, index, tree) {
|
||||
if (tree[indexArray[index]]) {
|
||||
if (index + 1 !== indexArray.length) {
|
||||
this.currentPath += tree[indexArray[index]].text + ' > ';
|
||||
} else {
|
||||
this.currentPath += tree[indexArray[index]].text;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < indexArray.length && tree[indexArray[index]].items) {
|
||||
this.getParents(indexArray, index + 1, tree[indexArray[index]].items);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
### Runnable example
|
||||
{% meta id:index height:620 %}
|
||||
{% embed_file treeview-show-parent-nodes-path/main.vue preview %}
|
||||
{% embed_file treeview-show-parent-nodes-path/main.js %}
|
||||
{% endmeta %}
|
Загрузка…
Ссылка в новой задаче