docs(kb): add KB articles for Grid, Chart, Upload and Editor (#394)

This commit is contained in:
Petar Todorov 2023-04-27 13:44:21 +03:00 коммит произвёл GitHub
Родитель 5b1dcd05d1
Коммит bd55e1b03f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
26 изменённых файлов: 1756 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,40 @@
---
title: Add custom line height tool inside the Native Editor.
description: An example demonstrating how to implement a custom line height tool inside the Native Editor component.
type: how-to
page_title: Add custom line height tool in the Native Editor | Kendo UI for Vue Native Editor
slug: editor-line-height-custom-tool
tags: editor, custom tool, line height, tools, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native</td>
</tr>
</tbody>
</table>
## Description
The current KB article demonstrates how to add a custom `line-height` tool inside the Native Editor
## Runnable example
{% meta height: 420 %}
{% embed_file editor-line-height-custom-tool/main.vue preview %}
{% embed_file editor-line-height-custom-tool/main.js %}
{% embed_file editor-line-height-custom-tool/content-basic.js %}
{% endmeta %}

Просмотреть файл

@ -0,0 +1,3 @@
const content = `<p>The Kendo UI for Vue Native Editor allows your users to edit HTML in a familiar, user-friendly way.<br />The Editor provides the core HTML editing engine, which includes text formatting, hyperlinks, and lists. The component <strong>outputs identical HTML</strong> across all major browsers, follows accessibility standards, and provides API for content manipulation.</p>`;
export default content;

Просмотреть файл

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,54 @@
<template>
<Editor
:tools="tools"
:default-content="content"
:content-style="{
height: '300px',
}"
>
<template v-slot:MyLineHeight="{ props }">
<fontsize v-bind="props" />
</template>
</Editor>
</template>
<script>
import {
Editor,
InlineFormat,
FontName,
} from '@progress/kendo-vue-editor';
import content from './content-basic';
const lineHeightSettings = {
style: 'line-height',
defaultItem: {
text: 'No Line Height',
value: '',
},
items: [
{ text: '2', value: '2' },
{ text: '3', value: '3' },
{ text: '4', value: '4' },
{ text: '5', value: '5' },
{ text: '6', value: '6' },
{ text: '7', value: '7' },
],
commandName: 'LineHeight',
};
export default {
components: {
Editor,
inlineformat: InlineFormat,
fontsize: FontName,
fontname: FontName,
},
data() {
return {
content: content,
tools: [{ render: 'MyLineHeight', props: lineHeightSettings }],
};
},
};
</script>

Просмотреть файл

@ -0,0 +1,89 @@
<template>
<td style="padding: 0; position: relative">
<span style="position: absolute; top: 25px; left: 140px; z-index: 10000">
{{ chartValue }}
</span>
<Chart style="height: 90px; margin-top: -20px" :transitions="false">
<ChartArea
:background="'#eee'"
:opacity="0"
:height="120"
:margin="-40"
:border="{ width: 0 }"
/>
<ChartValueAxis>
<ChartValueAxisItem
:reverse="true"
:max="700"
:labels="{ visible: false }"
:majorGridLines="{ visible: false }"
/>
</ChartValueAxis>
<ChartSeries>
<ChartSeriesItem
:color="'pink'"
:type="'bar'"
:spacing="0.25"
:data-items="firstSeries"
/>
</ChartSeries>
</Chart>
</td>
</template>
<script>
import {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
} from "@progress/kendo-vue-charts";
import "hammerjs";
export default {
components: {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
},
props: {
field: String,
dataItem: Object,
format: String,
className: String,
columnIndex: Number,
columnsCount: Number,
rowType: String,
level: Number,
expanded: Boolean,
editor: String,
},
computed: {
chartValue() {
return this.$props.dataItem.UnitsInStock > 800
? this.$props.dataItem.UnitsInStock - 800
: 0;
},
firstSeries() {
return [this.chartValue];
},
},
methods: {
change(e) {
this.$emit("change", e, e.target.value);
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,92 @@
<template>
<td style="padding: 0; position: relative">
<span style="position: absolute; top: 25px; left: 110px; z-index: 10000">
{{ chartValue }}
</span>
<Chart style="height: 90px; margin-top: -20px" :transitions="false">
<ChartArea
:background="'#eee'"
:opacity="0"
:height="120"
:margin="-40"
:border="{ width: 0 }"
/>
<ChartValueAxis>
<ChartValueAxisItem
:reverse="true"
:max="800"
:labels="{ visible: false }"
:majorGridLines="{ visible: false }"
/>
</ChartValueAxis>
<ChartSeries>
<ChartSeriesItem
:color="'pink'"
:type="'bar'"
:spacing="0.25"
:data-items="firstSeries"
/>
</ChartSeries>
</Chart>
</td>
</template>
<script>
import {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
} from "@progress/kendo-vue-charts";
import "hammerjs";
export default {
components: {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
},
props: {
field: String,
dataItem: Object,
format: String,
className: String,
columnIndex: Number,
columnsCount: Number,
rowType: String,
level: Number,
expanded: Boolean,
editor: String,
},
computed: {
chartValue() {
return this.$props.dataItem.UnitsInStock > 800
? 800
: this.$props.dataItem.UnitsInStock;
},
firstSeries() {
return [this.chartValue];
},
},
data() {
return {};
},
methods: {
change(e) {
this.$emit("change", e, e.target.value);
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,82 @@
<template>
<td style="padding: 0; position: relative">
<span style="position: absolute; top: 25px; left: 40px; z-index: 10000">
{{ dataItem["UnitsInStock"] }}
</span>
<Chart style="height: 90px; margin-top: -20px">
<ChartArea
:background="'#eee'"
:opacity="0"
:height="120"
:margin="-40"
:border="{ width: 0 }"
/>
<ChartValueAxis>
<ChartValueAxisItem
:max="100"
:labels="{ visible: false }"
:majorGridLines="{ visible: false }"
/>
</ChartValueAxis>
<ChartSeries>
<ChartSeriesItem
:type="'bar'"
:spacing="0.25"
:data-items="firstSeries"
/>
</ChartSeries>
</Chart>
</td>
</template>
<script>
import {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
} from "@progress/kendo-vue-charts";
import "hammerjs";
export default {
components: {
Chart,
ChartTitle,
ChartSeries,
ChartSeriesItem,
ChartCategoryAxis,
ChartCategoryAxisTitle,
ChartCategoryAxisItem,
ChartValueAxis,
ChartValueAxisItem,
ChartArea,
},
props: {
field: String,
dataItem: Object,
format: String,
className: String,
columnIndex: Number,
columnsCount: Number,
rowType: String,
level: Number,
expanded: Boolean,
editor: String,
},
data() {
return {
firstSeries: [this.$props.dataItem.UnitsInStock],
};
},
methods: {
change(e) {
this.$emit("change", e, e.target.value);
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,102 @@
<template>
<Grid
ref="grid"
:style="{ height: '360px' }"
:data-items="gridData"
:columns="columns"
>
<template v-slot:unitsCellTemplate="{ props }">
<UnitsCell :data-item="props.dataItem" :field="props.field" />
</template>
<template v-slot:unitsTemplate="{ props }">
<Units :data-item="props.dataItem" :field="props.field" />
</template>
<template v-slot:unitsCellReverseTemplate="{ props }">
<UnitCellReverse :data-item="props.dataItem" :field="props.field" />
</template>
</Grid>
</template>
<script>
import { Grid } from "@progress/kendo-vue-grid";
import { Button } from "@progress/kendo-vue-buttons";
import UnitsCell from "./UnitsCell";
import Units from "./Units";
import UnitCellReverse from "./UnitCellReverse";
var sampleProducts = [
{
ProductID: 1,
ProductName: "Chai",
UnitsInStock: 890,
Discontinued: false,
FirstOrderedOn: new Date(1996, 8, 20),
},
{
ProductID: 2,
ProductName: "Chang",
UnitsInStock: 400,
Discontinued: false,
FirstOrderedOn: new Date(1996, 7, 12),
},
{
ProductID: 3,
ProductName: "Aniseed Syrup",
UnitsInStock: 1300,
Discontinued: false,
FirstOrderedOn: new Date(1996, 8, 26),
},
{
ProductID: 4,
ProductName: "Chef Anton's Cajun Seasoning",
UnitsInStock: 1030,
Discontinued: false,
FirstOrderedOn: new Date(1996, 9, 19),
},
];
export default {
components: {
Grid: Grid,
UnitsCell,
UnitCellReverse,
Units,
kbutton: Button,
},
data: function () {
return {
gridData: sampleProducts.slice(0),
updatedData: [],
editID: null,
group: [{ field: "UnitsInStock" }],
expandedItems: [],
columns: [
{ field: "ProductID", editable: false, title: "ID", width: "80px" },
{ field: "ProductName", title: "Name" },
{
field: "FirstOrderedOn",
editor: "date",
title: "First Ordered",
format: "{0:d}",
},
{
field: "Discontinued",
title: "Units right to left",
cell: "unitsCellReverseTemplate",
width: "200px",
},
{
field: "UnitsInStock",
title: "Units",
width: "250px",
cell: "unitsTemplate",
},
{
field: "Discontinued",
title: "Units presented with Chart",
cell: "unitsCellTemplate",
},
],
};
},
};
</script>

Просмотреть файл

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,148 @@
<template>
<Grid
:data-items="products"
:filterable="true"
:filter="filter"
@filterchange="filterChange"
:columns="columns"
:filter-cell-render="filterRender"
>
<template v-slot:filterSlotTemplate="{ props, methods }">
<div>
Filter Slot:
<KInput
:style="{ width: '180px' }"
:value="inputValue"
@input="onInput"
/>
<KButton :style="{ 'margin-left': '15px' }" @click="onReset"
>Clear</KButton
>
</div>
</template>
</Grid>
</template>
<script>
import { Grid } from '@progress/kendo-vue-grid';
import { Input } from '@progress/kendo-vue-inputs';
import { Button } from '@progress/kendo-vue-buttons';
import { filterBy } from '@progress/kendo-data-query';
import { sampleProducts } from './products';
export default {
components: {
Grid,
KInput: Input,
KButton: Button,
},
data: function () {
return {
filter: {
logic: 'and',
filters: [],
},
columns: [
{ field: 'ProductID', filterable: false, title: 'ID', width: '50px' },
{
field: 'ProductName',
title: 'Product Name',
},
{
field: 'UnitsInStock',
filterCell: 'filterSlotTemplate',
width: '350px',
title: 'UnitsInStock',
},
{ field: 'UnitPrice', filter: 'numeric', title: 'UnitPrice' },
{ field: 'Discontinued', filter: 'boolean', title: 'Discontinued' },
],
inputValue: null,
};
},
computed: {
products: function () {
return filterBy(sampleProducts, this.filter);
},
},
methods: {
filterChange: function (ev) {
this.filter = ev.filter;
},
filterRender: function (h, defaultRendering, props, change) {
return defaultRendering;
},
onReset() {
this.inputValue = '';
this.filter = {
logic: 'and',
filters: [],
};
},
onInput(ev) {
this.inputValue = ev.target.value;
if (this.inputValue.length === 0) {
setTimeout(() => {
this.filter = {
logic: 'and',
filters: [],
};
});
}
let newFilter = [...this.filter.filters].filter(
(filter) => filter.field !== 'UnitsInStock'
);
const commaSeparatedValues = ev.target.value.split(',');
const equalFilters = [];
const rangeFilters = [];
commaSeparatedValues.forEach((ev) => {
if (Number(ev)) {
equalFilters.push({
field: 'UnitsInStock',
operator: 'eq',
value: ev,
});
} else {
const rangeValues = ev.split('-');
if (rangeValues[0] !== '') {
rangeFilters.push({
field: 'UnitsInStock',
operator: 'gte',
value: Number(rangeValues[0]),
});
rangeFilters.push({
field: 'UnitsInStock',
operator: 'lte',
value: Number(rangeValues[1]),
});
}
}
});
const newFilterDefinitions = [];
if (rangeFilters.length !== 0) {
newFilterDefinitions.push({
logic: 'and',
filters: [...rangeFilters],
});
}
if (equalFilters.length !== 0) {
newFilterDefinitions.push(...equalFilters);
}
newFilter.push({
field: 'UnitsInStock',
logic: 'or',
filters: newFilterDefinitions,
});
this.filter.filters = newFilter;
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,185 @@
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: 20,
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,206 @@
<template>
<div>
<GridColumnMenuSort
:column="column"
:sortable="sortable"
:sort="sort"
@closemenu="closeMenu"
@sortchange="sortChange"
/>
<GridColumnMenuFilter
:column="column"
:filterable="filterable"
:filter="filter"
@filterfocus="handleFocus"
@closemenu="closeMenu"
@expandchange="expandChange"
@filterchange="filterChange"
/>
<GridColumnMenuItemGroup>
<GridColumnMenuItem
:title="'Columns'"
:icon-class="'k-i-columns'"
@menuitemclick="onMenuItemClick"
/>
<GridColumnMenuItemContent :show="columnsExpanded">
<div class="k-column-list-wrapper">
<form @submit="onSubmit" @reset="onReset">
<div class="k-column-list">
<div
:key="idx"
class="k-column-list-item"
v-for="(column, idx) in currentColumns"
>
<span>
<input
:id="'column-visiblity-show-' + idx"
:class="'k-checkbox k-checkbox-md k-rounded-md'"
:type="'checkbox'"
:readOnly="true"
:disabled="!column.hidden && oneVisibleColumn"
:checked="!column.hidden"
@click="onToggleColumn(idx)"
/>
<label
:for="'column-visiblity-show-' + idx"
:class="'k-checkbox-label'"
:style="{ userSelect: 'none' }"
>
{{ column.title }} - {{ idx }}
</label>
</span>
</div>
</div>
<div class="k-columnmenu-actions">
<kbutton type="reset">Reset</kbutton>
<kbutton :theme-color="'primary'">Save</kbutton>
</div>
</form>
</div>
</GridColumnMenuItemContent>
</GridColumnMenuItemGroup>
<GridColumnMenuItemGroup>
<GridColumnMenuItemContent :show="true">
<div class="k-column-list-wrapper">
<div class="k-column-list">
<div
@click="columnLockUnlock(true)"
:class="['k-column-list-item', $props.locked ? 'k-disabled' : '']"
>
<span class="k-icon k-i-lock" /> Lock Column
</div>
<div
@click="columnLockUnlock(false)"
:class="[
'k-column-list-item',
!$props.locked ? 'k-disabled' : '',
]"
>
<span class="k-icon k-i-unlock" /> Unlock Column
</div>
</div>
</div>
</GridColumnMenuItemContent>
</GridColumnMenuItemGroup>
<GridColumnMenuItemGroup>
<GridColumnMenuItemContent :show="true">
<div class="k-column-list-wrapper">
<div class="k-column-list">
<div
@click="columnShowHide(true)"
:class="['k-column-list-item', $props.hidden ? 'k-disabled' : '']"
>
<span class="k-icon k-i-minus" /> Hide Column
</div>
</div>
</div>
</GridColumnMenuItemContent>
</GridColumnMenuItemGroup>
</div>
</template>
<script>
import {
GridColumnMenuFilter,
GridColumnMenuSort,
GridColumnMenuItemGroup,
GridColumnMenuItemContent,
GridColumnMenuItem,
} from '@progress/kendo-vue-grid';
import { Button } from '@progress/kendo-vue-buttons';
import { products } from './products';
export default {
props: {
column: Object,
sortable: [Boolean, Object],
sort: {
type: Array,
},
filter: Object,
filterable: Boolean,
locked: Boolean,
columns: Array,
},
data() {
return {
currentColumns: [],
columnsExpanded: false,
filterExpanded: false,
};
},
created() {
this.$data.currentColumns = this.$props.columns;
},
components: {
GridColumnMenuSort: GridColumnMenuSort,
GridColumnMenuFilter: GridColumnMenuFilter,
GridColumnMenuItemGroup: GridColumnMenuItemGroup,
GridColumnMenuItemContent: GridColumnMenuItemContent,
GridColumnMenuItem: GridColumnMenuItem,
kbutton: Button,
},
computed: {
oneVisibleColumn() {
return this.currentColumns.filter((c) => !c.hidden).length === 1;
},
},
methods: {
handleFocus(e) {
this.$emit('contentfocus', e);
},
onToggleColumn(id) {
this.currentColumns = this.currentColumns.map((column, idx) => {
return idx === id ? { ...column, hidden: !column.hidden } : column;
});
},
onReset(event) {
event.preventDefault();
const allColumns = this.$props.columns.map((col) => {
return {
...col,
hidden: false,
};
});
this.currentColumns = allColumns;
this.onSubmit();
},
onSubmit(event) {
if (event) {
event.preventDefault();
}
this.$emit('columnssubmit', this.currentColumns);
this.$emit('closemenu');
},
onMenuItemClick() {
const value = !this.columnsExpanded;
this.columnsExpanded = value;
this.filterExpanded = value ? false : this.filterExpanded;
},
onFilterExpandChange(value) {
this.filterExpanded = value;
this.columnsExpanded = value ? false : this.columnsExpanded;
},
expandChange() {
this.$emit('expandchange');
},
closeMenu() {
this.$emit('closemenu');
},
filterChange(newDescriptor, e) {
this.$emit('filterchange', newDescriptor);
},
sortChange(newDescriptor, e) {
this.$emit('sortchange', newDescriptor);
},
columnLockUnlock(state) {
this.$emit('lockchange', state);
this.$emit('closemenu');
},
columnShowHide(state) {
this.$emit('visibilitychange', state);
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,184 @@
<template>
<Grid
:data-items="result"
:take="dataState.take"
:skip="dataState.skip"
:sort="dataState.sort"
:filter="dataState.filter"
@datastatechange="dataStateChange"
@columnreorder="handleColumnReorder"
:columns="lockedColumns"
:sortable="true"
:pageable="true"
:reorderable="true"
:page-size="8"
:style="{ width: '500px' }"
>
<template v-slot:myTemplate="{ props }">
<div>
<custom
:column="props.column"
:filterable="props.filterable"
:filter="props.filter"
:sortable="props.sortable"
:sort="props.sort"
:columns="columns"
:locked="isColumnLocked(props.column.field)"
@sortchange="(e) => props.onSortchange(e)"
@lockchange="(e) => lockChange(e, props.column)"
@visibilitychange="(e) => visibilityChange(e, props.column)"
@filterchange="(e) => props.onFilterchange(e)"
@closemenu="(e) => props.onClosemenu(e)"
@contentfocus="(e) => props.onContentfocus(e)"
@columnssubmit="onColumnsSubmit"
/>
</div>
</template>
</Grid>
</template>
<script>
import { Grid } from '@progress/kendo-vue-grid';
import { process } from '@progress/kendo-data-query';
import ColumnMenu from './ColumnMenu.vue';
import { products } from './products.js';
export default {
components: {
Grid: Grid,
custom: ColumnMenu,
},
data: function () {
return {
result: [],
dataState: {
take: 0,
skip: 0,
},
columns: [
{
title: 'Product Id',
field: 'ProductID',
filter: 'numeric',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 100,
locked: true,
},
{
title: 'Product Name',
field: 'ProductName',
filter: 'text',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 200,
},
{
title: 'Quantity Per Unit',
field: 'QuantityPerUnit',
filter: 'numeric',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 100,
},
{
title: 'Unit Price',
field: 'UnitPrice',
filter: 'numeric',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 100,
},
{
title: 'Units In Stock',
field: 'UnitsInStock',
filter: 'numeric',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 100,
},
{
title: 'Discontinued',
field: 'Discontinued',
filter: 'boolean',
locked: false,
columnMenu: 'myTemplate',
hidden: false,
width: 100,
},
],
};
},
created: function () {
this.createDataState({
take: 8,
skip: 0,
});
},
computed: {
lockedColumns() {
if (this.columns.filter((ev) => ev.locked)) {
const columns = [...this.columns];
return columns
.sort((a, b) => Number(b.locked) - Number(a.locked))
.map((e) => {
return { ...e, orderIndex: undefined };
});
} else {
this.columns;
}
},
},
methods: {
handleColumnReorder(event) {
const lastLockedindex = this.lockedColumns.findLastIndex((e) => e.locked);
const updatedColumns = event.columns
.sort((a, b) => Number(a.orderIndex) - Number(b.orderIndex))
.map((e, index) => {
const newLockedState =
event.prev > lastLockedindex && event.next <= lastLockedindex
? true
: event.prev <= lastLockedindex && event.next > lastLockedindex
? false
: e.locked;
return {
...e,
locked: index === event.next ? newLockedState : e.locked,
};
});
this.columns = updatedColumns;
},
isColumnLocked(columnName) {
return this.columns.filter((ev) => ev.field === columnName)[0].locked;
},
handleFilterChange: function (filter) {
this.result = process(products.slice(0), { filter: filter });
},
createDataState(dataState) {
this.result = process(products.slice(0), dataState);
this.dataState = dataState;
},
dataStateChange(event) {
this.createDataState(event.data);
},
onColumnsSubmit(columnsState) {
this.columns = columnsState;
},
lockChange(state, columnName) {
const columnToLock = this.columns.filter(
(ev) => ev.field === columnName.field
)[0];
columnToLock.locked = state;
},
visibilityChange(state, columnName) {
this.columns.filter((ev) => ev.field === columnName.field)[0].hidden =
state;
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,140 @@
const products = [
{
ProductID: 1,
ProductName: 'Chai',
SupplierID: 1,
CategoryID: 1,
QuantityPerUnit: '10 boxes x 20 bags',
UnitPrice: 18.0,
UnitsInStock: 39,
UnitsOnOrder: 0,
ReorderLevel: 10,
Discontinued: false,
Category: {
CategoryID: 1,
CategoryName: 'Beverages',
Description: 'Soft drinks, coffees, teas, beers, and ales',
},
},
{
ProductID: 2,
ProductName: 'Chang',
SupplierID: 1,
CategoryID: 1,
QuantityPerUnit: '24 - 12 oz bottles',
UnitPrice: 19.0,
UnitsInStock: 17,
UnitsOnOrder: 40,
ReorderLevel: 25,
Discontinued: false,
Category: {
CategoryID: 1,
CategoryName: 'Beverages',
Description: 'Soft drinks, coffees, teas, beers, and ales',
},
},
{
ProductID: 3,
ProductName: 'Aniseed Syrup',
SupplierID: 1,
CategoryID: 2,
QuantityPerUnit: '12 - 550 ml bottles',
UnitPrice: 10.0,
UnitsInStock: 13,
UnitsOnOrder: 70,
ReorderLevel: 25,
Discontinued: false,
Category: {
CategoryID: 2,
CategoryName: 'Condiments',
Description: 'Sweet and savory sauces, relishes, spreads, and seasonings',
},
},
{
ProductID: 4,
ProductName: "Chef Anton's Cajun Seasoning",
SupplierID: 2,
CategoryID: 2,
QuantityPerUnit: '48 - 6 oz jars',
UnitPrice: 22.0,
UnitsInStock: 53,
UnitsOnOrder: 0,
ReorderLevel: 0,
Discontinued: false,
Category: {
CategoryID: 2,
CategoryName: 'Condiments',
Description: 'Sweet and savory sauces, relishes, spreads, and seasonings',
},
},
{
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',
},
},
{
ProductID: 6,
ProductName: "Grandma's Boysenberry Spread",
SupplierID: 3,
CategoryID: 2,
QuantityPerUnit: '12 - 8 oz jars',
UnitPrice: 25.0,
UnitsInStock: 120,
UnitsOnOrder: 0,
ReorderLevel: 25,
Discontinued: false,
Category: {
CategoryID: 2,
CategoryName: 'Condiments',
Description: 'Sweet and savory sauces, relishes, spreads, and seasonings',
},
},
{
ProductID: 7,
ProductName: "Uncle Bob's Organic Dried Pears",
SupplierID: 3,
CategoryID: 7,
QuantityPerUnit: '12 - 1 lb pkgs.',
UnitPrice: 30.0,
UnitsInStock: 15,
UnitsOnOrder: 0,
ReorderLevel: 10,
Discontinued: false,
Category: {
CategoryID: 7,
CategoryName: 'Produce',
Description: 'Dried fruit and bean curd',
},
},
{
ProductID: 8,
ProductName: 'Northwoods Cranberry Sauce',
SupplierID: 3,
CategoryID: 2,
QuantityPerUnit: '12 - 12 oz jars',
UnitPrice: 40.0,
UnitsInStock: 6,
UnitsOnOrder: 0,
ReorderLevel: 0,
Discontinued: false,
Category: {
CategoryID: 2,
CategoryName: 'Condiments',
Description: 'Sweet and savory sauces, relishes, spreads, and seasonings',
},
},
];
export { products };

Просмотреть файл

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,71 @@
<template>
<div>
<Grid
ref="grid"
:style="{ height: '520px' }"
:data-items="products"
:selected-field="selectedField"
:columns="columns"
@rowclick="onRowClick"
>
</Grid>
</div>
</template>
<script>
import { Grid } from "@progress/kendo-vue-grid";
export default {
components: {
Grid: Grid,
},
data: function () {
return {
selectedField: "selected",
selectedID: 1,
products: [],
columns: [
{ field: "ProductID", title: "ID", width: "50px" },
{ field: "ProductName", title: "Product Name" },
{ field: "UnitPrice", filter: "numeric", title: "Unit Price" },
{ field: "UnitsInStock", title: "Units In Stock" },
],
};
},
methods: {
onRowClick(event) {
if (event.event.metaKey || event.event.ctrlKey || event.event.shiftKey) {
event.dataItem[this.selectedField] =
!event.dataItem[this.selectedField];
}
},
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)],
UnitsInStock: Math.floor(Math.random() * 100),
}));
},
},
mounted() {
this.products = this.createRandomData(1000);
},
};
</script>

Просмотреть файл

@ -0,0 +1,64 @@
<template>
<UploadListMultiItem
:files="files"
:async="async"
:disabled="disabled"
@cancel="onCancel"
@remove="onRemove"
@retry="onRetry"
/>
<Dialog v-if="visibleDialog" :title="'Please confirm'" @close="toggleDialog">
<p :style="{ margin: '25px', textAlign: 'center' }">
Are you sure you want to remove the file?
</p>
<DialogActionsBar>
<KButton @click="toggleDialog">No</KButton>
<KButton :theme-color="'primary'" @click="confirmRemove">Yes</KButton>
</DialogActionsBar>
</Dialog>
</template>
<script>
import { UploadListMultiItem } from '@progress/kendo-vue-upload';
import { Dialog, DialogActionsBar } from '@progress/kendo-vue-dialogs';
import { Button as KButton } from '@progress/kendo-vue-buttons';
export default {
components: {
UploadListMultiItem,
KButton,
Dialog,
DialogActionsBar,
},
props: {
files: Array,
disabled: Boolean,
async: Object,
},
emits: ['retry', 'remove', 'cancel'],
data() {
return {
visibleDialog: false,
uid: undefined,
};
},
methods: {
toggleDialog() {
this.visibleDialog = false;
},
onRetry(uid) {
this.$emit('retry', uid);
},
onRemove(uid) {
this.visibleDialog = true;
this.uid = uid;
},
confirmRemove() {
this.$emit('remove', this.uid);
},
onCancel(uid) {
this.$emit('cancel', uid);
},
},
};
</script>

Просмотреть файл

@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './main.vue'
createApp(App).mount('#app')

Просмотреть файл

@ -0,0 +1,38 @@
<template>
<div>
<upload
:list="customListItemUI"
:default-files="[]"
:batch="false"
:multiple="true"
:with-credentials="false"
:save-url="'https://demos.telerik.com/kendo-ui/service-v4/upload/save'"
:remove-url="'https://demos.telerik.com/kendo-ui/service-v4/upload/remove'"
>
<template v-slot:myTemplate="{props}">
<custom
:files="props.files"
:async="props.async"
@cancel="props.onCancel"
@remove="props.onRemove"
@retry="props.onRetry"/>
</template>
</upload>
</div>
</template>
<script>
import { Upload } from '@progress/kendo-vue-upload';
import CustomList from './CustomList';
export default {
components: {
upload: Upload,
'custom': CustomList
},
data () {
return {
customListItemUI: 'myTemplate'
};
}
}
</script>

Просмотреть файл

@ -0,0 +1,41 @@
---
title: Add Native Chart in multiple Grid columns based on a data item value.
description: The current KB article shows how we can display a Native Chart as a background inside multiple Native Grid columns.
type: how-to
page_title: Add Chart as a background of multiple Native Grid columns based on a data item value.
slug: grid-display-chart-in-multiple-grid-columns
tags: grid, chart, background, multiple column, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native</td>
</tr>
</tbody>
</table>
## Description
The current KB article shows how we can display a `Native Chart` as a background inside multiple `Native Grid` columns based on a data item value.
## Runnable example
{% meta height: 420 %}
{% embed_file grid-display-chart-in-multiple-grid-columns/main.vue preview %}
{% embed_file grid-display-chart-in-multiple-grid-columns/main.js %}
{% embed_file grid-display-chart-in-multiple-grid-columns/UnitCellReverse.vue %}
{% embed_file grid-display-chart-in-multiple-grid-columns/Units.vue %}
{% embed_file grid-display-chart-in-multiple-grid-columns/UnitsCell.vue %}
{% endmeta %}

Просмотреть файл

@ -0,0 +1,41 @@
---
title: Filter the Kendo UI for Vue Native Grid's data using a comma separated values.
description: A a sample project that shows how to implement a custom row filter inside the Native Grid that allows data filtering using comma separated values.
type: how-to
page_title: Filter the Native Grid using comma separated values | Kendo UI for Vue Native Grid
slug: grid-filtering-comma-separated-values
tags: grid, filter, filtering, row filter, comma separated, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native</td>
</tr>
</tbody>
</table>
## Description
The current KB article demonstrates how you can implement a custom row filter inside the Native Grid that filter's its data using comma separated values.
## Runnable example
To test the following example start adding values in the filter input of the `UnitsInStock` column. Ex: "`13,120,17`"
{% meta id:index height:600 %}
{% embed_file grid-filtering-comma-separated-values/main.vue preview %}
{% embed_file grid-filtering-comma-separated-values/main.js %}
{% embed_file grid-filtering-comma-separated-values/products.js %}
{% endmeta %}

Просмотреть файл

@ -0,0 +1,45 @@
---
title: Make a reordered column locked when dropping it over a locked column
description: See how to automatically lock a given Grid column when reordering it among locked columns
type: how-to
page_title: Select Grid rows when Shift, Ctrl or Command(for Mac) buttons are pressed | Kendo UI for Vue Native Grid
slug: grid-reordering-locked-columns
tags: grid, reorder, locked column, columns, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native</td>
</tr>
</tbody>
</table>
## Description
This KB is an example that mimics the way the locked columns are internally handled by the Kendo UI for jQuery Grid.
In the current scenario when we reorder a column and drop it over a locked column or on the left of a locked column, then the column that is being reordered is becoming also a locked column.
## Runnable example
To test the following example reorder one of the columns different from `Product Id` by moving it before the `Product Id` column. The result will be that the reordered column will also become locked.
{% meta height: 600 %}
{% embed_file grid-reordering-locked-columns/main.vue preview %}
{% embed_file grid-reordering-locked-columns/main.js %}
{% embed_file grid-reordering-locked-columns/ColumnMenu.vue %}
{% embed_file grid-reordering-locked-columns/products.js %}
{% endmeta %}

Просмотреть файл

@ -0,0 +1,55 @@
---
title: Select Native Grid Rows When Specific Buttons are Pressed.
description: An example demonstrating how the rows' selection inside the Native Grid component can be controlled and based on specific keyboard keys.
type: how-to
page_title: Select Grid rows when Shift, Ctrl or Command(for Mac) buttons are pressed | Kendo UI for Vue Native Grid
slug: grid-select-row-when-shift-ctrl-command-are-pressed
tags: grid, selection, specific key, shift, ctrl, command, key, press, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native</td>
</tr>
</tbody>
</table>
## Description
This KB article demonstrates how you can limit the rows' selection of the Native Grid by pressing specific keyboard keys. In the following example the rows of the Native Grid can be selected or deselected only when the Shift, Ctrl or Command(for Mac) keyboard buttons are pressed.
**KB sections**
* [Solution description](#toc-solution-description)
* [Runnable example](#toc-runnable-example)
## Solution description
To achieve the following scenario, we use the [onRowClick]({% slug api_grid_gridprops %}#toc-onrowclick) event of the Native Grid and the following code:
```
onRowClick(event) {
if (event.event.metaKey || event.event.ctrlKey || event.event.shiftKey) {
event.dataItem[this.selectedField] =
!event.dataItem[this.selectedField];
}
}
```
### Runnable example
To test the following example press `Ctrl`, `Shift` or `Command(for Mac)` buttons and click on selected Grid row.
{% meta id:index height:600 %}
{% embed_file grid-select-row-when-shift-ctrl-command-are-pressed/main.vue preview %}
{% embed_file grid-select-row-when-shift-ctrl-command-are-pressed/main.js %}
{% endmeta %}

Просмотреть файл

@ -0,0 +1,51 @@
---
title: Add confirmation Dialog when removing a file inside the Upload's list.
description: A project that shows how you can add a confirmation Dialog when removing an uploaded file.
type: how-to
page_title: Learn how to add a confirmation Dialog when removing an uploaded file in the Upload component.
slug: upload-add-confirmation-dialog-on-remove
tags: upload, list, remove file, confirmation, dialog, custom, template, kendovue, native
res_type: kb
category: knowledge-base
---
## Environment
<table>
<tbody>
<tr>
<td>Product Version</td>
<td>3.10.0</td>
</tr>
<tr>
<td>Product</td>
<td>Progress® Kendo UI for Vue Native Upload</td>
</tr>
</tbody>
</table>
## Description
This Knowledge base(KB) article demonstrates how we can add a confirmation Dialog when removing a file inside the list of the Upload component.
**KB sections**
* [Solution description](#toc-solution-description)
* [Runnable example](#toc-runnable-example)
## Solution description
To achieve the demonstrated behavior, we need to use the [list]({% slug api_upload_uploadprops %}#toc-list) prop of the Upload component and pass a custom template to it. More details about the usage of the list property can be found on our [Upload customization demo]({% slug rendering_upload %}).
### Runnable example
To test the following example, select files for Upload and click on one of the "X" buttons inside the Upload's list.
{% meta id:index height:480 %}
{% embed_file upload-add-confirmation-dialog-on-remove/main.vue preview %}
{% embed_file upload-add-confirmation-dialog-on-remove/CustomList.vue %}
{% embed_file upload-add-confirmation-dialog-on-remove/main.js %}
{% endmeta %}