Skip to content

Commit 685befd

Browse files
authored
CardView: Fix a state issue with the searchPanel.text property, prevent re-renderings (9GXIgWhP) (#29878)
1 parent c138366 commit 685befd

File tree

6 files changed

+48
-25
lines changed

6 files changed

+48
-25
lines changed

e2e/testcafe-devextreme/tests/cardView/search/api.functional.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,18 @@ test('searchPanel.placeholder API', async (t) => {
7575
});
7676
});
7777

78-
// TODO: unskip when update text property state issue is resolved
79-
test.skip('searchPanel.text API', async (t) => {
78+
test('searchPanel.text API', async (t) => {
8079
const cardView = new CardView('#container');
8180
const searchBox = cardView.getSearchBox();
8281

8382
await t
84-
.expect(searchBox.getInput().getAttribute('value'))
83+
.expect(searchBox.getInput().value)
8584
.eql('rt');
8685

8786
await cardView.apiOption('searchPanel.text', '');
8887

8988
await t
90-
.expect(searchBox.getInput().getAttribute('value'))
89+
.expect(searchBox.getInput().value)
9190
.eql('');
9291
}).before(async () => {
9392
await createWidget('dxCardView', {
@@ -99,6 +98,23 @@ test.skip('searchPanel.text API', async (t) => {
9998
});
10099
});
101100

101+
test('searchPanel.text API from UI', async (t) => {
102+
const cardView = new CardView('#container');
103+
const searchBox = cardView.getSearchBox().getInput();
104+
105+
await t
106+
.typeText(searchBox, 'rt')
107+
.expect(cardView.apiOption('searchPanel.text')).eql('rt');
108+
}).before(async () => {
109+
await createWidget('dxCardView', {
110+
...baseConfig,
111+
searchPanel: {
112+
...baseConfig.searchPanel,
113+
text: '',
114+
},
115+
});
116+
});
117+
102118
test('searchPanel.searchVisibleColumnsOnly API', async (t) => {
103119
const cardView = new CardView('#container');
104120
const searchInput = cardView.getSearchBox().getInput();
-355 Bytes
Loading
35 Bytes
Loading
-63 Bytes
Loading

packages/devextreme/js/__internal/grids/new/grid_core/search/controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export class SearchController {
2828

2929
public readonly searchTextOption = this.options.twoWay('searchPanel.text');
3030

31+
public readonly searchPlaceholder = this.options.oneWay('searchPanel.placeholder');
32+
33+
public readonly searchWidth = this.options.oneWay('searchPanel.width');
34+
3135
private readonly searchVisibleColumnsOnly = this.options.oneWay('searchPanel.searchVisibleColumnsOnly');
3236

3337
public readonly searchFilter = computed(() => {
Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import type { TextBoxInstance } from '@js/ui/text_box';
2-
import type { ReadonlySignal } from '@preact/signals-core';
3-
import { computed } from '@preact/signals-core';
2+
import type { Signal } from '@preact/signals-core';
3+
import { effect, signal } from '@preact/signals-core';
44
import { ToolbarController } from '@ts/grids/new/grid_core/toolbar/controller';
55

66
import { OptionsController } from '../options_controller/options_controller';
77
import { SearchController } from './controller';
88
import { SearchUIController } from './controller_ui';
9-
import type { SearchFieldProps } from './types';
109
import { addSearchTextBox } from './utils';
1110

1211
export class SearchView {
@@ -17,36 +16,40 @@ export class SearchView {
1716
SearchController,
1817
] as const;
1918

20-
private searchTextBox: TextBoxInstance | null = null;
19+
private readonly searchTextBox: Signal<null | TextBoxInstance> = signal(null);
2120

2221
constructor(
2322
private readonly options: OptionsController,
2423
private readonly toolbarController: ToolbarController,
2524
private readonly searchUIController: SearchUIController,
2625
private readonly searchController: SearchController,
2726
) {
27+
const toolbarItem = addSearchTextBox(
28+
{
29+
placeholder: this.searchController.searchPlaceholder.value,
30+
value: this.searchController.searchTextOption.value,
31+
width: this.searchController.searchWidth.value,
32+
onValueChanged: (text): void => {
33+
this.searchController.updateSearchText(text);
34+
},
35+
},
36+
(component) => {
37+
this.searchTextBox.value = component;
38+
},
39+
);
2840
this.toolbarController.addDefaultItem(
29-
computed(() => addSearchTextBox(
30-
this.getProps().value,
31-
(component) => { this.searchTextBox = component; },
32-
)),
41+
signal(toolbarItem),
3342
this.options.oneWay('searchPanel.visible'),
3443
);
3544

36-
this.searchUIController.registerCallback('focusSearchTextBox', () => {
37-
this.searchTextBox?.focus();
45+
effect(() => {
46+
this.searchTextBox.value?.option('value', this.searchController.searchTextOption.value);
47+
this.searchTextBox.value?.option('placeholder', this.searchController.searchPlaceholder.value);
48+
this.searchTextBox.value?.option('width', this.searchController.searchWidth.value);
3849
});
39-
}
4050

41-
protected getProps(): ReadonlySignal<SearchFieldProps> {
42-
return computed(() => ({
43-
placeholder: this.options.oneWay('searchPanel.placeholder').value,
44-
// TODO: resolve update cycle: editor - option - editor
45-
// value: this.searchController.searchTextOption.value,
46-
width: this.options.oneWay('searchPanel.width').value,
47-
onValueChanged: (text): void => {
48-
this.searchController.updateSearchText(text);
49-
},
50-
}));
51+
this.searchUIController.registerCallback('focusSearchTextBox', () => {
52+
this.searchTextBox.value?.focus();
53+
});
5154
}
5255
}

0 commit comments

Comments
 (0)