Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
<template>
<div>
<DxTreeList
id="treeList"
:data-source="dataSource"
:word-wrap-enabled="true"
:show-borders="true"
:focused-row-enabled="true"
v-model:focused-row-key="focusedRowKey"
parent-id-expr="Task_Parent_ID"
has-items-expr="Has_Items"
@focused-row-changed="onFocusedRowChanged"
>
<DxColumn
data-field="Task_ID"
width="100"
alignment="left"
/>
<DxColumn
:min-width="120"
data-field="Task_Assigned_Employee_ID"
caption="Assigned"
>
<DxLookup
:data-source="taskEmployees"
value-expr="ID"
display-expr="Name"
/>
</DxColumn>
<DxColumn
data-field="Task_Status"
caption="Status"
width="160"
/>
<DxColumn
data-field="Task_Start_Date"
caption="Start Date"
data-type="date"
width="160"
/>
<DxColumn
data-field="Task_Due_Date"
caption="Due Date"
data-type="date"
width="160"
/>
</DxTreeList>
<div class="task-info">
<div class="info">
<div class="task-subject">{{ taskSubject }}</div>
<span class="task-assigned">{{ taskAssigned }}</span>
<span class="start-date">{{ startDate }}</span>
</div>
<div class="progress">
<span class="task-status">{{ taskStatus }}</span>
<span class="task-progress">{{ taskProgress }}</span>
</div>
</div>
<div class="options">
<div class="caption">Options</div>
<div class="option">
<span>Focused row key </span>
<DxNumberBox
id="taskId"
:min="1"
:max="182"
:step="0"
v-model:value="focusedRowKey"
:input-attr="{ 'aria-label': 'Focused Row Key' }"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import {
DxTreeList, DxColumn, DxLookup, DxTreeListTypes,
} from 'devextreme-vue/tree-list';
import DxNumberBox from 'devextreme-vue/number-box';
import { createStore } from 'devextreme-aspnet-data-nojquery';
const url = 'https://js.devexpress.com/Demos/Mvc/api/TreeListTasks';
const taskSubject = ref('');
const taskAssigned = ref('');
const startDate = ref('');
const taskStatus = ref('');
const taskProgress = ref('');
const dataSource = createStore({
key: 'Task_ID',
loadUrl: `${url}/Tasks`,
onBeforeSend(_, ajaxOptions) {
ajaxOptions.xhrFields = { withCredentials: true };
},
});
const taskEmployees = createStore({
key: 'ID',
loadMode: 'raw',
loadUrl: `${url}/TaskEmployees`,
});
const focusedRowKey = ref(45);
function onFocusedRowChanged(e: DxTreeListTypes.FocusedCellChangedEvent) {
const rowData = e.row && e.row.data;
let cellValue;
let assigned;
if (rowData) {
cellValue = e.component.cellValue(e.row.rowIndex, 'Assigned');
taskEmployees.byKey(cellValue).done((item) => {
assigned = item.Name;
});
taskSubject.value = rowData.Task_Subject;
taskAssigned.value = assigned;
startDate.value = new Date(rowData.Task_Start_Date).toLocaleDateString();
taskStatus.value = rowData.Task_Status;
taskProgress.value = rowData.Task_Completion
? `${rowData.Task_Completion}%`
: '';
}
}
</script>
window.exports = window.exports || {};
window.config = {
transpiler: 'plugin-babel',
meta: {
'*.vue': {
loader: 'vue-loader',
},
'*.ts': {
loader: 'demo-ts-loader',
},
'*.svg': {
loader: 'svg-loader',
},
'devextreme/time_zone_utils.js': {
'esModule': true,
},
'devextreme/localization.js': {
'esModule': true,
},
'devextreme/viz/palette.js': {
'esModule': true,
},
'devextreme-aspnet-data-nojquery': {
'esModule': true,
},
'openai': {
'esModule': true,
},
},
paths: {
'project:': '../../../../',
'npm:': 'https://unpkg.com/',
'bundles:': '../../../../bundles/',
'externals:': '../../../../bundles/externals/',
},
map: {
'vue': 'npm:vue@3.4.27/dist/vue.esm-browser.js',
'@vue/shared': 'npm:@vue/shared@3.4.27/dist/shared.cjs.prod.js',
'vue-loader': 'npm:dx-systemjs-vue-browser@1.1.1/index.js',
'demo-ts-loader': 'project:utils/demo-ts-loader.js',
'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js',
'svg-loader': 'project:utils/svg-loader.js',
'devextreme-aspnet-data-nojquery': 'npm:devextreme-aspnet-data-nojquery@3.0.0/index.js',
'mitt': 'npm:mitt/dist/mitt.umd.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign',
'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs',
'devextreme-vue': 'npm:devextreme-vue@link:../../packages/devextreme-vue/npm/cjs',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12',
'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js',
'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js',
'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js',
'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
// Prettier
'prettier/standalone': 'npm:prettier@2.8.8/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
},
packages: {
'devextreme-vue': {
main: 'index.js',
},
'devextreme': {
defaultExtension: 'js',
},
'devextreme/events/utils': {
main: 'index',
},
'devextreme/events': {
main: 'index',
},
'es6-object-assign': {
main: './index.js',
defaultExtension: 'js',
},
},
packageConfigPaths: [
'npm:@devextreme/*/package.json',
'npm:@devextreme/runtime@3.0.12/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
},
};
System.config(window.config);
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
#treeList {
max-height: 400px;
}
.task-info {
font-family: "Segoe UI";
min-height: 100px;
display: flex;
flex-wrap: nowrap;
border: 2px solid rgba(0, 0, 0, 0.1);
padding: 16px;
box-sizing: border-box;
align-items: center;
justify-content: space-between;
}
.info {
display: flex;
flex-direction: column;
}
.task-subject {
line-height: 29px;
font-size: 18px;
font-weight: bold;
}
.progress {
display: flex;
flex-direction: column;
white-space: pre;
min-width: 105px;
}
.task-progress {
line-height: 42px;
font-size: 40px;
font-weight: bold;
}
.options {
margin-top: 20px;
padding: 20px;
background-color: rgba(191, 191, 191, 0.15);
position: relative;
}
.caption {
font-size: 18px;
font-weight: 500;
}
.option {
margin-top: 10px;
}
.option > .dx-numberbox {
width: 200px;
display: inline-block;
vertical-align: middle;
}
.option > span {
margin-right: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="https://unpkg.com/typescript@5.4.5/lib/typescript.js"></script>
<script type="module">
import * as vueCompilerSFC from "https://unpkg.com/@vue/compiler-sfc@3.4.27/dist/compiler-sfc.esm-browser.js";
window.vueCompilerSFC = vueCompilerSFC;
</script>
<script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script>
<script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
System.import("./index.ts");
</script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
In this demo, the row with the 45
key is focused initially. You can specify the focusedRowKey
property via the input field below the TreeList. The onFocusedRowChanged function is used to display additional information below the component when the focused row changes.