const DemoApp = angular.module('DemoApp', ['dx']);
DemoApp.controller('DemoController', ($scope) => {
$scope.dataGridOptions = {
dataSource: DevExpress.data.AspNet.createStore({
key: 'ID',
loadUrl: `${url}/Tasks`,
updateUrl: `${url}/UpdateTask`,
insertUrl: `${url}/InsertTask`,
onBeforeSend(method, ajaxOptions) {
ajaxOptions.xhrFields = { withCredentials: true };
},
}),
showBorders: true,
paging: {
enabled: true,
pageSize: 15,
},
headerFilter: {
visible: true,
},
searchPanel: {
visible: true,
},
editing: {
mode: 'cell',
allowUpdating: true,
allowAdding: true,
},
onRowInserted(e) {
e.component.navigateToRow(e.key);
},
columns: [{
dataField: 'Owner',
width: 150,
allowSorting: false,
lookup: {
dataSource: employees,
valueExpr: 'ID',
displayExpr: 'FullName',
},
validationRules: [{ type: 'required' }],
editCellTemplate: 'dropDownBoxEditorTemplate',
}, {
dataField: 'AssignedEmployee',
caption: 'Assignees',
width: 200,
allowSorting: false,
editCellTemplate: 'tagBoxEditorTemplate',
lookup: {
dataSource: employees,
valueExpr: 'ID',
displayExpr: 'FullName',
},
validationRules: [{ type: 'required' }],
cellTemplate(container, options) {
const noBreakSpace = '\u00A0';
const text = (options.value || []).map((element) => options.column.lookup.calculateCellValue(element)).join(', ');
container.text(text || noBreakSpace).attr('title', text);
},
calculateFilterExpression(filterValue, selectedFilterOperation, target) {
if (target === 'search' && typeof (filterValue) === 'string') {
return [this.dataField, 'contains', filterValue];
}
return function (data) {
return (data.AssignedEmployee || []).indexOf(filterValue) !== -1;
};
},
}, {
dataField: 'Subject',
validationRules: [{ type: 'required' }],
}, {
dataField: 'Status',
lookup: {
dataSource: statuses,
valueExpr: 'id',
displayExpr: 'name',
},
validationRules: [{ type: 'required' }],
width: 200,
editorOptions: {
itemTemplate: 'statusTemplate',
},
},
],
};
$scope.initTagBoxEditor = function (data) {
return {
dataSource: employees,
value: data.value,
valueExpr: 'ID',
displayExpr: 'FullName',
showSelectionControls: true,
maxDisplayedTags: 3,
showMultiTagOnly: false,
applyValueMode: 'useButtons',
searchEnabled: true,
onValueChanged(e) {
data.setValue(e.value);
},
onSelectionChanged() {
data.component.updateDimensions();
},
};
};
$scope.initDropDownBoxEditor = function (data) {
return {
dropDownOptions: { width: 500 },
dataSource: employees,
value: data.value,
valueExpr: 'ID',
displayExpr: 'FullName',
contentTemplate: 'contentTemplate',
};
};
$scope.initContent = function (data, component) {
return {
dataSource: employees,
remoteOperations: true,
columns: ['FullName', 'Title', 'Department'],
hoverStateEnabled: true,
scrolling: { mode: 'virtual' },
height: 250,
selection: { mode: 'single' },
selectedRowKeys: [data.value],
focusedRowEnabled: true,
focusedRowKey: data.value,
onSelectionChanged(selectionChangedArgs) {
component.option('value', selectionChangedArgs.selectedRowKeys[0]);
data.setValue(selectionChangedArgs.selectedRowKeys[0]);
if (selectionChangedArgs.selectedRowKeys.length > 0) {
component.close();
}
},
};
};
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<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=1.0" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script>
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/22.2.6/css/dx.light.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script>window.angular || document.write(decodeURIComponent('%3Cscript src="js/angular.min.js"%3E%3C/script%3E'))</script>
<script src="https://cdn3.devexpress.com/jslib/22.2.6/js/dx.all.js"></script>
<script src="https://unpkg.com/devextreme-aspnet-data@2.9.0/js/dx.aspnet.data.js"></script>
<script src="data.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="index.js"></script>
</head>
<body class="dx-viewport">
<div class="demo-container" ng-app="DemoApp" ng-controller="DemoController">
<div id="gridContainer" dx-data-grid="dataGridOptions" dx-item-alias="row">
<div data-options="dxTemplate:{ name: 'statusTemplate' }">
<div ng-if="row != null">
<img ng-src="{{'images/icons/status-' + row.id + '.svg'}}" class="status-icon middle" />
<span class="middle">{{row.name}}</span>
</div>
<span ng-if="row == null"> (All) </span>
</div>
<div data-options="dxTemplate:{ name: 'tagBoxEditorTemplate'}">
<div dx-tag-box="initTagBoxEditor(row)"></div>
</div>
<div data-options="dxTemplate:{ name: 'dropDownBoxEditorTemplate'}">
<div dx-drop-down-box="initDropDownBoxEditor(row)" dx-item-alias="item">
<div data-options="dxTemplate:{ name: 'contentTemplate'}">
<div dx-data-grid="initContent(row, item.component)"></div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
.status-icon {
height: 16px;
width: 16px;
display: inline-block;
margin-right: 8px;
}
.middle {
vertical-align: middle;
}
const statuses = [{
id: 1, name: 'Not Started',
}, {
id: 2, name: 'In Progress',
}, {
id: 3, name: 'Deferred',
}, {
id: 4, name: 'Need Assistance',
}, {
id: 5, name: 'Completed',
},
];
const url = 'https://js.devexpress.com/Demos/Mvc/api/CustomEditors';
const employees = DevExpress.data.AspNet.createStore({
key: 'ID',
loadUrl: `${url}/Employees`,
onBeforeSend(method, ajaxOptions) {
ajaxOptions.xhrFields = { withCredentials: true };
},
});