Skip to content

Commit 559a620

Browse files
Fix: jQuery implementation
1 parent b0816da commit 559a620

File tree

7 files changed

+192
-238
lines changed

7 files changed

+192
-238
lines changed

jQuery/.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
node_modules/*
2+
src/orig_index.js
3+
src/orig_index.html

jQuery/package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jQuery/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"browser-sync": "^3.0.2",
2828
"devextreme": "25.1.3",
2929
"devextreme-dist": "25.1.3",
30+
"devextreme-aspnet-data": "^2.9.0",
3031
"jquery": "^3.7.1"
3132
}
3233
}

jQuery/src/index.html

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4-
<title>DevExtreme jQuery app</title>
4+
<title>DevExtreme jQuery site</title>
55
<meta charset="utf-8" />
66
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
7-
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
88
<link rel="icon" href="/favicon.ico" />
9-
<link rel="stylesheet" type="text/css" href="../node_modules/devextreme-dist/css/dx.material.blue.light.compact.css" />
9+
<link rel="stylesheet" type="text/css" href="../node_modules/devextreme-dist/css/dx.light.css" />
1010
<link rel="stylesheet" type="text/css" href="index.css" />
11-
<script type="text/javascript" src="../node_modules/jquery/dist/jquery.js"></script>
12-
<script type="text/javascript" src="../node_modules/devextreme-dist/js/dx.all.js"></script>
13-
<script type="text/javascript" src="index.js"></script>
11+
<script src="../node_modules/jquery/dist/jquery.js"></script>
12+
<script src="../node_modules/devextreme-dist/js/dx.all.js"></script>
13+
<script src="../node_modules/devextreme-aspnet-data/js/dx.aspnet.data.js"></script>
14+
<script src="index.js"></script>
15+
<style>
16+
.demo-container .dx-fieldset {
17+
height: 500px;
18+
}
19+
</style>
1420
</head>
15-
16-
<body class="dx-viewport">
17-
<div class="demo-container">
18-
<div id="btn"></div>
21+
<body class="dx-viewport demo-container">
22+
<div class="dx-fieldset">
23+
<div class="dx-field">
24+
<div class="dx-field-label"> DropDownBox with search and embedded DataGrid </div>
25+
<div class="dx-field-value">
26+
<div id="gridBox"></div>
27+
</div>
28+
</div>
1929
</div>
2030
</body>
2131
</html>

jQuery/src/index.js

Lines changed: 160 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,164 @@
11
$(() => {
2-
let count = 0;
3-
$('#btn').dxButton({
4-
text: `Click count: ${count}`,
5-
onClick(e) {
6-
count += 1;
7-
e.component.option('text', `Click count: ${count}`);
2+
let dataGridInstance;
3+
let searchTimerId;
4+
let gridFirstLoadCompleted = false;
5+
6+
const dataSource = new DevExpress.data.DataSource({
7+
store: makeAsyncDataSource(),
8+
searchExpr: ['StoreCity', 'StoreState', 'Employee'],
9+
});
10+
11+
const $gridBox = $('#gridBox');
12+
13+
$gridBox.dxDropDownBox({
14+
value: 35711,
15+
valueExpr: 'OrderNumber',
16+
displayExpr: (item) => (item ? `${item.Employee}: ${item.StoreState} - ${item.StoreCity} <${item.OrderNumber}>` : ''),
17+
acceptCustomValue: true,
18+
openOnFieldClick: false,
19+
valueChangeEvent: '',
20+
showClearButton: true,
21+
dataSource: makeAsyncDataSource(),
22+
placeholder: 'Select a value...',
23+
dropDownOptions: { height: 300 },
24+
onInput: (e) => {
25+
clearTimeout(searchTimerId);
26+
searchTimerId = setTimeout(() => {
27+
const dropDownBox = e.component;
28+
const text = dropDownBox.option('text');
29+
const opened = dropDownBox.option('opened');
30+
dataSource.searchValue(text);
31+
if (opened && isSearchIncomplete(dropDownBox)) {
32+
dataSource.load().done((items) => {
33+
if (items.length > 0 && dataGridInstance) {
34+
dataGridInstance.option('focusedRowKey', items[0].OrderNumber);
35+
}
36+
});
37+
} else {
38+
dropDownBox.open();
39+
}
40+
}, 500);
41+
},
42+
onOpened: (e) => {
43+
const dropDownBox = e.component;
44+
if (dropDownBox.isKeyDown) {
45+
const contentReadyHandler = (args) => {
46+
const grid = args.component;
47+
grid.focus();
48+
grid.off('contentReady', contentReadyHandler);
49+
};
50+
if (!gridFirstLoadCompleted) {
51+
dataGridInstance.on('contentReady', contentReadyHandler);
52+
} else {
53+
const optionChangedHandler = (args) => {
54+
const grid = args.component;
55+
if (args.name === 'focusedRowKey' || args.name === 'focusedColumnIndex') {
56+
grid.off('optionChanged', optionChangedHandler);
57+
grid.focus();
58+
}
59+
};
60+
dataGridInstance.on('optionChanged', optionChangedHandler);
61+
dataGridInstance.option('focusedRowIndex', 0);
62+
}
63+
dropDownBox.isKeyDown = false;
64+
return;
65+
}
66+
if (gridFirstLoadCompleted && isSearchIncomplete(dropDownBox)) {
67+
dataSource.load().done((items) => {
68+
if (items.length > 0) {
69+
dataGridInstance.option('focusedRowKey', items[0].OrderNumber);
70+
}
71+
dropDownBox.focus();
72+
});
73+
}
74+
},
75+
onClosed: (e) => {
76+
const dropDownBox = e.component;
77+
const value = dropDownBox.option('value');
78+
const searchValue = dataSource.searchValue();
79+
if (isSearchIncomplete(dropDownBox)) {
80+
dropDownBox.option('value', value === '' ? null : '');
81+
}
82+
if (searchValue) {
83+
dataSource.searchValue(null);
84+
}
85+
},
86+
onKeyDown: (e) => {
87+
const dropDownBox = e.component;
88+
if (e.event.keyCode !== 40) return;
89+
if (!dropDownBox.option('opened')) {
90+
dropDownBox.isKeyDown = true;
91+
dropDownBox.open();
92+
} else if (dataGridInstance) {
93+
dataGridInstance.focus();
94+
}
95+
},
96+
contentTemplate: (e, container) => {
97+
const dropDownBox = e.component;
98+
const value = dropDownBox.option('value');
99+
const $dataGridContainer = $('<div>');
100+
container.append($dataGridContainer);
101+
$dataGridContainer.dxDataGrid({
102+
dataSource,
103+
hoverStateEnabled: true,
104+
paging: { enabled: true, pageSize: 10 },
105+
focusedRowIndex: 0,
106+
focusedRowEnabled: true,
107+
autoNavigateToFocusedRow: false,
108+
onContentReady: (_args) => {
109+
if (!gridFirstLoadCompleted) {
110+
gridFirstLoadCompleted = true;
111+
dropDownBox.focus();
112+
}
113+
},
114+
remoteOperations: true,
115+
scrolling: { mode: 'virtual' },
116+
selection: { mode: 'single' },
117+
selectedRowKeys: [value],
118+
height: '100%',
119+
width: '100%',
120+
columnWidth: 100,
121+
onKeyDown: (args) => {
122+
const grid = args.component;
123+
if (args.event.keyCode === 13) {
124+
grid.selectRows([grid.option('focusedRowKey')], false);
125+
}
126+
},
127+
onSelectionChanged: (args) => {
128+
const keys = args.selectedRowKeys;
129+
dropDownBox.option('value', keys.length ? keys[0] : null);
130+
},
131+
columns: [
132+
{ dataField: 'OrderNumber', caption: 'ID', dataType: 'number' },
133+
{ dataField: 'OrderDate', dataType: 'date', format: 'shortDate' },
134+
{ dataField: 'StoreCity', dataType: 'string' },
135+
{ dataField: 'StoreState', dataType: 'string' },
136+
{ dataField: 'Employee', dataType: 'string' },
137+
{ dataField: 'SaleAmount', dataType: 'number', format: { type: 'currency', precision: 2 } },
138+
],
139+
});
140+
dataGridInstance = $dataGridContainer.dxDataGrid('instance');
141+
dropDownBox.on('valueChanged', (args) => {
142+
clearTimeout(searchTimerId);
143+
dataGridInstance.option('selectedRowKeys', args.value ? [args.value] : []);
144+
dropDownBox.close();
145+
});
146+
return container;
8147
},
9148
});
10149
});
150+
151+
function makeAsyncDataSource() {
152+
return DevExpress.data.AspNet.createStore({
153+
key: 'OrderNumber',
154+
loadUrl: 'https://js.devexpress.com/Demos/WidgetsGalleryDataService/api/orders',
155+
});
156+
}
157+
158+
function isSearchIncomplete(dropDownBox) {
159+
let displayValue = dropDownBox.option('displayValue');
160+
let text = dropDownBox.option('text');
161+
text = text && text.length && text;
162+
displayValue = displayValue && displayValue.length && displayValue[0];
163+
return text !== displayValue;
164+
}

jQuery/src/orig_index.html

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)