Skip to content

Commit

Permalink
TagBox: fix tag rendering when valueExpr is a function (T1234032) (#2…
Browse files Browse the repository at this point in the history
…8667)

Signed-off-by: Anton Kuznetsov <[email protected]>
Co-authored-by: Anton Kuznetsov <[email protected]>
  • Loading branch information
nikkithelegendarypokemonster and ksercs authored Jan 24, 2025
1 parent d4535f7 commit 6c7c002
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { equalByValue, getKeyHash } from '@js/core/utils/common';
import { compileGetter } from '@js/core/utils/data';
import { isObject, isString } from '@js/core/utils/type';
import { isFunction, isObject, isString } from '@js/core/utils/type';

export const SelectionFilterCreator = function (selectedItemKeys, isSelectAll?: boolean) {
this.getLocalFilter = function (keyGetter, equalKeys, equalByReference, keyExpr) {
Expand All @@ -24,7 +24,7 @@ export const SelectionFilterCreator = function (selectedItemKeys, isSelectAll?:
filterExpr.push(isSelectAll ? 'and' : 'or');
}

if (isString(keyExpr)) {
if (isString(keyExpr) || isFunction(keyExpr)) {
filterExprPart = getFilterForPlainKey(keyExpr, key);
} else {
filterExprPart = getFilterForCompositeKey(keyExpr, key);
Expand Down
1 change: 1 addition & 0 deletions packages/devextreme/js/__internal/ui/m_tag_box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,7 @@ const TagBox = (SelectBox as any).inherit({

_getSelectedItemsFromList(values) {
const listSelectedItems = this._list?.option('selectedItems');

let selectedItems = [];
if (values.length === listSelectedItems?.length) {
selectedItems = this._filterSelectedItems(listSelectedItems, values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6659,6 +6659,94 @@ QUnit.module('dataSource integration', moduleSetup, () => {
assert.ok(true, 'TagBox rendered');
});

QUnit.test('Tagbox should render tag correctly when hideSelectedItems = true and valueExpr is a function (T1234032)', function(assert) {
const data = [
{ id: 1, scheme: 'schema1', name: 'name1' },
{ id: 2, scheme: 'schema1', name: 'name2' }
];
const $tagBox = $('#tagBox').dxTagBox({
dataSource: data,
valueExpr(x) {
return x && x.name + ' ' + x.scheme;
},
displayExpr: 'name',
hideSelectedItems: true,
opened: true
});
const instance = $tagBox.dxTagBox('instance');
const $listItem = getListItems($tagBox);
$listItem.trigger('dxclick');

const $tags = instance.$element().find(`.${TAGBOX_TAG_CLASS}`);
assert.strictEqual($tags.length, 1, 'One tag is rendered after click');
assert.strictEqual($tags.eq(0).text().trim(), 'name1', 'Correct tag text is rendered');
assert.strictEqual(instance.option('value')[0], 'name1 schema1', 'Correct value is stored');

const $secondItem = getListItems($tagBox);
$secondItem.trigger('dxclick');

const $updatedTags = instance.$element().find(`.${TAGBOX_TAG_CLASS}`);
assert.strictEqual($updatedTags.length, 2, 'Two tags are rendered after selecting the second item');
assert.strictEqual($updatedTags.eq(1).text().trim(), 'name2', 'Second tag is rendered correctly');
assert.strictEqual(instance.option('value')[1], 'name2 schema1', 'Correct value is stored');
});

QUnit.test('TagBox should render initial tags correctly even if items are not loaded yet and valueExpr is a function', function(assert) {
const data = [
{ name: 'name1', scheme: 'schema1', value: 1 },
{ name: 'name2', scheme: 'schema2', value: 2 },
];

const dataSource = new DataSource({
store: new ArrayStore(data),
paginate: true,
pageSize: 1,
});

const $tagBox = $('#tagBox').dxTagBox({
dataSource,
displayExpr: 'name',
hideSelectedItems: true,
valueExpr(x) {
return x && `${x.name} ${x.scheme}`;
},
value: ['name1 schema1', 'name2 schema2'],
opened: true
});

const instance = $tagBox.dxTagBox('instance');
const $tags = instance.$element().find(`.${TAGBOX_TAG_CLASS}`);

assert.strictEqual($tags.length, 2, 'Two tag is rendered after init');
assert.strictEqual($tags.eq(0).text().trim(), 'name1', 'Correct first tag text is rendered');
assert.strictEqual($tags.eq(1).text().trim(), 'name2', 'Correct second tag text is rendered');
assert.strictEqual(instance.option('value')[0], 'name1 schema1', 'Correct first value is stored');
assert.strictEqual(instance.option('value')[1], 'name2 schema2', 'Correct second value is stored');
});

QUnit.test('Tagbox should render initial value correctly with function valueExpr', function(assert) {
const data = [
{ id: 1, scheme: 'schema1', name: 'name1' },
{ id: 2, scheme: 'schema1', name: 'name2' }
];

const instance = $('#tagBox').dxTagBox({
dataSource: data,
valueExpr(x) {
return x && `${x.name} ${x.scheme}`;
},
displayExpr: 'name',
hideSelectedItems: true,
value: ['name1 schema1'],
opened: true
}).dxTagBox('instance');

const $tags = instance.$element().find(`.${TAGBOX_TAG_CLASS}`);
assert.strictEqual($tags.length, 1, 'One tag is rendered initially');
assert.strictEqual($tags.eq(0).text().trim(), 'name1', 'Correct tag text is rendered');
assert.strictEqual(instance.option('value')[0], 'name1 schema1', 'Initial value is correct');
});

QUnit.test('TagBox should correctly handle disposing on data loading', function(assert) {
assert.expect(1);

Expand Down Expand Up @@ -6817,9 +6905,8 @@ QUnit.module('performance', () => {
const $item = $(getList(tagBox).find('.dx-list-item').eq(0));

$item.trigger('dxclick');

const filter = load.lastCall.args[0].filter;
assert.ok($.isFunction(filter), 'filter is function');
assert.ok($.isFunction(filter[0]), 'filter is function');
});

QUnit.test('loadOptions.filter should be correct when user filter is also used', function(assert) {
Expand Down

0 comments on commit 6c7c002

Please sign in to comment.