Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const SELECTORS = {
editorCell: 'dx-editor-cell',
editorContainer: 'dx-editor-container',
widget: 'dx-widget',
};

export class FilterCellModel {
constructor(protected readonly root: HTMLElement | null) {}

public getElement(): HTMLElement | null {
return this.root;
}

public getEditor<T>(EditorModel: new (element: HTMLElement) => T): T {
const editorElement = this.root?.querySelector(`.${SELECTORS.editorContainer} .${SELECTORS.widget}`) as HTMLElement;
return new EditorModel(editorElement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import { ConfirmationDialogModel } from './confirmation_dialog';
import { EditFormModel } from './edit_form';
import { FilterPanelModel } from './filter_panel';
import { DataRowModel } from './row/data_row';
import { FilterRowModel } from './row/filter_row';
import { GroupRowModel } from './row/group_row';

const SELECTORS = {
headerRowClass: 'dx-header-row',
dataRowClass: 'dx-data-row',
groupRowClass: 'dx-group-row',
filterRowClass: 'filter-row',
aiDialog: 'dx-aidialog',
aiPromptEditor: 'dx-ai-prompt-editor',
toast: 'dx-toast',
Expand Down Expand Up @@ -90,6 +92,13 @@ export abstract class GridCoreModel<TInstance = GridBase | CardView> {
);
}

public getFilterRow(): FilterRowModel {
const filterRowElement = this.root.querySelector(
`.${this.addWidgetPrefix(SELECTORS.filterRowClass)}`,
);
return new FilterRowModel(filterRowElement as HTMLElement);
}

public getGroupRows(): NodeListOf<HTMLElement> {
return this.root.querySelectorAll(`.${SELECTORS.groupRowClass}`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class BaseRowModel {
constructor(protected readonly root: HTMLElement | null) {}

public getElement(): HTMLElement | null {
return this.root;
}

public getCells(): NodeListOf<HTMLElement> {
return this.root?.querySelectorAll('td') as NodeListOf<HTMLElement>;
}

public getCell(columnIndex: number): HTMLElement | null {
return this.getCells()?.[columnIndex] ?? null;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { BaseRowModel } from './base_row';

const SELECTORS = {
editRow: 'dx-edit-row',
deleteRowButton: 'dx-link-delete',
undeleteRowButton: 'dx-link-undelete',
};

export class DataRowModel {
export class DataRowModel extends BaseRowModel {
public readonly isEditRow: boolean;

constructor(protected readonly root: HTMLElement | null) {
constructor(root: HTMLElement | null) {
super(root);
this.isEditRow = !!this.root?.classList.contains(SELECTORS.editRow);
}

public getElement(): HTMLElement | null {
return this.root;
}

public getDeleteButton(): HTMLElement {
const row = this.getElement() as HTMLElement;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { FilterCellModel } from '../cell/filter_cell';
import { BaseRowModel } from './base_row';

export class FilterRowModel extends BaseRowModel {
public getFilterCell(columnIndex: number): FilterCellModel {
return new FilterCellModel(this.getCell(columnIndex));
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { BaseRowModel } from './base_row';

const SELECTORS = {
expandCell: 'dx-command-expand',
};

export class GroupRowModel {
constructor(protected readonly root: HTMLElement | null) {
}

public getElement(): HTMLElement | null {
return this.root;
}

export class GroupRowModel extends BaseRowModel {
public getExpandCell(): HTMLElement {
const row = this.getElement() as HTMLElement;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import '@js/ui/tag_box';

import {
afterEach, beforeEach, describe, expect, it,
} from '@jest/globals';
import type { EditorPreparingEvent } from '@js/ui/data_grid';
import { TagBoxModel } from '@ts/ui/__tests__/__mock__/model/tag_box';

import {
afterTest,
beforeTest,
createDataGrid,
flushAsync,
} from '../../__tests__/__mock__/helpers/utils';

describe('FilterRow', () => {
beforeEach(beforeTest);
afterEach(afterTest);

describe('TagBox in filterRow with lookup column (T1306840)', () => {
it('should display tags in TagBox after selecting filter values', async () => {
// arrange
const lookupDataSource = [
{ Value: 0, Text: 'A' },
{ Value: 1, Text: 'B' },
{ Value: 2, Text: 'C' },
];

const { component } = await createDataGrid({
dataSource: [
{ ID: 1, test: 0 },
{ ID: 2, test: 2 },
{ ID: 3, test: 1 },
],
keyExpr: 'ID',
columns: [{
dataField: 'test',
lookup: {
dataSource: lookupDataSource,
displayExpr: 'Text',
valueExpr: 'Value',
},
}],
filterRow: { visible: true },
onEditorPreparing(e: EditorPreparingEvent) {
if (e.parentType === 'filterRow' && e.dataField === 'test') {
e.editorName = 'dxTagBox';
e.editorOptions.dataSource = lookupDataSource;
e.editorOptions.displayExpr = 'Text';
e.editorOptions.valueExpr = 'Value';
e.editorOptions.showSelectionControls = true;
e.editorOptions.applyValueMode = 'useButtons';
}
},
});

await flushAsync();

// act
const filterCell = component.getFilterRow().getFilterCell(0);
const tagBox = filterCell.getEditor(TagBoxModel);
tagBox.setValue([0, 2]);

await flushAsync();

// assert
expect(tagBox.getValue()).toEqual([0, 2]);
expect(tagBox.getTags()).toHaveLength(2);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const FILTER_MODIFIED_CLASS = 'dx-filter-modified';
const EDITORS_INPUT_SELECTOR = 'input:not([type=\'hidden\'])';

const BETWEEN_OPERATION_DATA_TYPES = ['date', 'datetime', 'number'];
const MULTISELECT_EDITOR_NAMES = ['dxTagBox', 'dxDateRangeBox', 'dxCalendar', 'dxRangeSlider'];

function isOnClickApplyFilterMode(that) {
return that.option('filterRow.applyFilter') === 'onClick';
Expand Down Expand Up @@ -124,9 +125,20 @@ const getColumnSelectedFilterOperation = function (that, column) {
}
};

const isValidFilterValue = function (filterValue, column) {
if (column && BETWEEN_OPERATION_DATA_TYPES.includes(column.dataType) && Array.isArray(filterValue)) {
return false;
const hasMultiselectEditor = function ($editorContainer): boolean {
const editor = getEditorInstance($editorContainer);
// @ts-expect-error
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change import Editor to import Editor from '@ts/ui/editor/editor';
internal types contain NAME property, and it would be possible to remove @ts-expect-error

return !editor || MULTISELECT_EDITOR_NAMES.includes(editor.NAME);
};

const isValidFilterValue = function (filterValue, column, $editorContainer): boolean {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add types to arguments, please

if (Array.isArray(filterValue)) {
if (hasMultiselectEditor($editorContainer)) {
return true;
}
if (BETWEEN_OPERATION_DATA_TYPES.includes(column?.dataType)) {
return false;
}
}

return filterValue !== undefined;
Expand All @@ -137,15 +149,20 @@ const getFilterValue = function (that, columnIndex, $editorContainer) {
const filterValue = getColumnFilterValue(that, column);
const isFilterRange = $editorContainer.closest(`.${that.addWidgetPrefix(FILTER_RANGE_OVERLAY_CLASS)}`).length;
const isRangeStart = $editorContainer.hasClass(that.addWidgetPrefix(FILTER_RANGE_START_CLASS));
const isBetween = getColumnSelectedFilterOperation(that, column) === 'between';

if (filterValue && Array.isArray(filterValue) && getColumnSelectedFilterOperation(that, column) === 'between') {
if (filterValue && Array.isArray(filterValue) && isBetween) {
if (isRangeStart) {
return filterValue[0];
}
return filterValue[1];
}

return !isFilterRange && isValidFilterValue(filterValue, column) ? filterValue : null;
if (isFilterRange || !isValidFilterValue(filterValue, column, $editorContainer)) {
return null;
}

return filterValue;
};

const normalizeFilterValue = function (that, filterValue, column, $editorContainer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type dxTagBox from '@js/ui/tag_box';
import TagBox from '@js/ui/tag_box';

const TAG_CLASS = 'dx-tag';

export class TagBoxModel {
constructor(protected readonly root: HTMLElement) {}

public getInstance(): dxTagBox {
return TagBox.getInstance(this.root) as dxTagBox;
}

public getValue(): (string | number)[] {
return this.getInstance().option('value') as (string | number)[];
}

public setValue(value: (string | number)[]): void {
this.getInstance().option('value', value);
}

public getInput(): HTMLInputElement {
return this.root.querySelector('input') as HTMLInputElement;
}

public getTags(): NodeListOf<HTMLElement> {
return this.root.querySelectorAll(`.${TAG_CLASS}`);
}
}
Loading