Skip to content

Commit a125625

Browse files
committed
Form: fix get item by path (T1311534)
1 parent d52b2ab commit a125625

File tree

4 files changed

+143
-31
lines changed

4 files changed

+143
-31
lines changed

packages/devextreme/js/__internal/ui/form/form.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,11 +1448,11 @@ class Form extends Widget<FormProperties> {
14481448
_getItemByField(field: string | {
14491449
fieldName: string;
14501450
fieldPath: string[];
1451-
}, items: PreparedItem[]): PreparedItem | false {
1451+
}, items: PreparedItem[]): PreparedItem | null {
14521452
const fieldParts = isObject(field) ? field : this._getFieldParts(field);
14531453
const { fieldName } = fieldParts;
14541454
const { fieldPath } = fieldParts;
1455-
let resultItem: PreparedItem | false = false;
1455+
let resultItem: PreparedItem | null = null;
14561456

14571457
if (items.length) {
14581458
each(items, (_index: number, item: PreparedItem): boolean => {
@@ -1491,34 +1491,24 @@ class Form extends Widget<FormProperties> {
14911491
fieldName: string;
14921492
fieldPath: string[];
14931493
} {
1494-
const fieldSeparator = '.';
1495-
let fieldName = field;
1496-
let separatorIndex = fieldName.indexOf(fieldSeparator);
1497-
const resultPath = [];
1498-
1499-
while (separatorIndex !== -1) {
1500-
// @ts-expect-error ts-error
1501-
resultPath.push(fieldName.substr(0, separatorIndex));
1502-
fieldName = fieldName.substr(separatorIndex + 1);
1503-
separatorIndex = fieldName.indexOf(fieldSeparator);
1504-
}
1494+
const [fieldName, ...fieldPath] = field.split('.').reverse();
15051495

15061496
return {
15071497
fieldName,
1508-
fieldPath: resultPath.reverse(),
1498+
fieldPath,
15091499
};
15101500
}
15111501

15121502
_getItemByFieldPath(
15131503
path: string[],
15141504
fieldName: string,
15151505
item: Item,
1516-
): Item | false {
1506+
): Item | null {
15171507
const { itemType } = item;
15181508
const subItemsField = this._getSubItemField(itemType);
15191509

15201510
const isItemWithSubItems = itemType === 'group' || itemType === 'tabbed' || (item as TabItem).title;
1521-
let result: Item | false = false;
1511+
let result: Item | null = null;
15221512

15231513
do {
15241514
if (isItemWithSubItems) {
@@ -1534,7 +1524,7 @@ class Form extends Widget<FormProperties> {
15341524
pathNode = path.pop();
15351525
}
15361526

1537-
if (!path.length) {
1527+
if (!path.length && nameWithoutSpaces === pathNode) {
15381528
result = this._getItemByField(fieldName, item[subItemsField]);
15391529

15401530
// eslint-disable-next-line max-depth
@@ -1543,10 +1533,15 @@ class Form extends Widget<FormProperties> {
15431533
}
15441534
}
15451535

1546-
if (!isGroupWithName || (isGroupWithName && nameWithoutSpaces === pathNode)) {
1536+
const isGroupPathNodeOrUnnamed = !isGroupWithName
1537+
|| (isGroupWithName && nameWithoutSpaces === pathNode);
1538+
1539+
if (isGroupPathNodeOrUnnamed && path.length) {
1540+
result = this._searchItemInEverySubItem(path, fieldName, item[subItemsField]);
1541+
15471542
// eslint-disable-next-line max-depth
1548-
if (path.length) {
1549-
result = this._searchItemInEverySubItem(path, fieldName, item[subItemsField]);
1543+
if (!result) {
1544+
break;
15501545
}
15511546
}
15521547
} else {
@@ -1565,20 +1560,17 @@ class Form extends Widget<FormProperties> {
15651560
path: string[],
15661561
fieldName: string,
15671562
items: Item[],
1568-
): Item | false {
1569-
let result: Item | false = false;
1563+
): Item | null {
1564+
let result: Item | null = null;
15701565
each(items, (_index: number, groupItem: GroupItem): boolean => {
15711566
result = this._getItemByFieldPath(path.slice(), fieldName, groupItem);
1567+
15721568
if (result) {
15731569
return false;
15741570
}
15751571
return true;
15761572
});
15771573

1578-
if (!result) {
1579-
return false;
1580-
}
1581-
15821574
return result;
15831575
}
15841576

packages/devextreme/js/__internal/ui/form/form.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const tryGetTabPath = (fullPath: string): string => {
6262

6363
export const getItemPath = (
6464
items: PreparedItem[],
65-
item: PreparedItem | false,
65+
item: PreparedItem | null,
6666
isTabs?: boolean,
6767
): string => {
6868
if (!item) {

packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.API.update_items_dynamically.tests.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,19 +2057,19 @@ module('Align labels', () => {
20572057
}]
20582058
});
20592059

2060-
testWrapper.setItemOption('title1.group1.description', 'visible', false);
2060+
testWrapper.setItemOption('title1.group2.description', 'visible', false);
20612061
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 0, etalonLabelText: 'Home Address' });
20622062
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 1, etalonLabelText: 'Last Name' });
20632063

2064-
testWrapper.setItemOption('title1.group1.homeAddress', 'visible', false);
2064+
testWrapper.setItemOption('title1.group2.homeAddress', 'visible', false);
20652065
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 0, etalonLabelText: 'Name' });
20662066
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 1, etalonLabelText: 'Last Name' });
20672067

2068-
testWrapper.setItemOption('title1.group1.description', 'visible', true);
2068+
testWrapper.setItemOption('title1.group2.description', 'visible', true);
20692069
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 0, etalonLabelText: 'Description' });
20702070
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 1, etalonLabelText: 'Last Name' });
20712071

2072-
testWrapper.setItemOption('title1.group1.homeAddress', 'visible', true);
2072+
testWrapper.setItemOption('title1.group2.homeAddress', 'visible', true);
20732073
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 0, etalonLabelText: 'Description' });
20742074
testWrapper.checkLabelsWidthInGroup({ columnIndex: 0, groupColumnIndex: 1, etalonLabelText: 'Home Address' });
20752075
});

packages/devextreme/testing/tests/DevExpress.ui.widgets.form/form.tests.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2623,6 +2623,126 @@ QUnit.test('Use \'itemOption\' with groups and one group has empty caption (T359
26232623
assert.equal($testContainer.find('.' + FORM_GROUP_CAPTION_CLASS).last().text(), 'custom', 'new caption rendered');
26242624
});
26252625

2626+
QUnit.test('Use \'itemOption\' with path when items have same name or caption (T1311534)', function(assert) {
2627+
const targetField = {
2628+
itemType: 'simple',
2629+
name: 'Target',
2630+
editorType: 'dxTextBox',
2631+
};
2632+
2633+
const targetGroup = {
2634+
itemType: 'group',
2635+
caption: 'Target',
2636+
items: [
2637+
{ itemType: 'simple', name: 'Field1', editorType: 'dxTextBox', },
2638+
{ itemType: 'simple', name: 'Field2', editorType: 'dxTextBox', },
2639+
{ itemType: 'simple', name: 'Field3', editorType: 'dxTextBox', },
2640+
],
2641+
};
2642+
2643+
const targetFieldInGroup = {
2644+
...targetField,
2645+
caption: 'Target in Group'
2646+
};
2647+
2648+
const form = $('#form').dxForm({
2649+
formData: {},
2650+
items: [
2651+
{
2652+
itemType: 'group',
2653+
name: 'ContainerGroup',
2654+
items: [
2655+
{ itemType: 'simple', name: 'Field4', editorType: 'dxTextBox', },
2656+
targetGroup,
2657+
]
2658+
},
2659+
{
2660+
itemType: 'group',
2661+
name: 'FieldGroup',
2662+
items: [
2663+
targetFieldInGroup,
2664+
{ itemType: 'simple', name: 'Field5', editorType: 'dxTextBox', },
2665+
],
2666+
},
2667+
targetField,
2668+
]
2669+
}).dxForm('instance');
2670+
2671+
assert.deepEqual(form.itemOption('Target'), targetField, 'Simple item retrieved by name');
2672+
assert.deepEqual(form.itemOption('ContainerGroup.Target'), targetGroup, 'Group item in group retrieved by path');
2673+
assert.deepEqual(form.itemOption('FieldGroup.Target'), targetFieldInGroup, 'Simple item in group retrieved by path');
2674+
});
2675+
2676+
QUnit.test('Use \'itemOption\' with path when items have same name in named and unnamed groups (T1311534)', function(assert) {
2677+
const targetField = {
2678+
itemType: 'simple',
2679+
name: 'Target',
2680+
editorType: 'dxTextBox',
2681+
};
2682+
2683+
const targetFieldInGroup = {
2684+
...targetField,
2685+
caption: 'Target in Group'
2686+
};
2687+
2688+
const form = $('#form').dxForm({
2689+
formData: {},
2690+
items: [
2691+
{
2692+
itemType: 'group',
2693+
name: 'FieldGroup',
2694+
items: [
2695+
targetFieldInGroup,
2696+
{ itemType: 'simple', name: 'Field5', editorType: 'dxTextBox', },
2697+
],
2698+
},
2699+
{
2700+
itemType: 'group',
2701+
items: [
2702+
{ itemType: 'simple', name: 'Field4', editorType: 'dxTextBox', },
2703+
targetField,
2704+
]
2705+
},
2706+
]
2707+
}).dxForm('instance');
2708+
2709+
assert.deepEqual(form.itemOption('Target'), targetField, 'Simple item in unnamed group retrieved by name');
2710+
assert.deepEqual(form.itemOption('FieldGroup.Target'), targetFieldInGroup, 'Simple item in group retrieved by path');
2711+
});
2712+
2713+
QUnit.test('Use \'itemOption\' with path in nested groups (T1311534)', function(assert) {
2714+
const targetField = {
2715+
itemType: 'simple',
2716+
name: 'Target',
2717+
editorType: 'dxTextBox',
2718+
};
2719+
2720+
const targetFieldInGroup = {
2721+
...targetField,
2722+
caption: 'Target in Group'
2723+
};
2724+
2725+
const form = $('#form').dxForm({
2726+
formData: {},
2727+
items: [{
2728+
itemType: 'group',
2729+
items: [
2730+
{
2731+
itemType: 'group',
2732+
name: 'FieldGroup',
2733+
items: [
2734+
targetFieldInGroup,
2735+
{ itemType: 'simple', name: 'Field5', editorType: 'dxTextBox', },
2736+
],
2737+
},
2738+
{ itemType: 'simple', name: 'Field4', editorType: 'dxTextBox', },
2739+
]
2740+
}]
2741+
}).dxForm('instance');
2742+
2743+
assert.deepEqual(form.itemOption('FieldGroup.Target'), targetFieldInGroup, 'Simple item in group retrieved by path');
2744+
});
2745+
26262746
QUnit.test('Use \'itemOption\' with tabs', function(assert) {
26272747
const $testContainer = $('#form').dxForm({
26282748
formData: { EmployeeID: 1, LastName: 'John', FirstName: 'Dow', BirthData: '01/01/1970', HireDate: '12/11/1995', Country: 'USA', City: 'Phoenix', Region: 'Arizona', Title: 'Ms' },

0 commit comments

Comments
 (0)