Skip to content

Commit 0a95175

Browse files
authored
Merge branch 'master' into update-node-versions
2 parents f3ff61f + 2985131 commit 0a95175

7 files changed

Lines changed: 122 additions & 20 deletions

File tree

projects/igniteui-angular/core/src/data-operations/expressions-tree-util.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FilteringLogic, IFilteringExpression } from './filtering-expression.interface';
22
import { FilteringExpressionsTree, IFilteringExpressionsTree } from './filtering-expressions-tree';
3-
import { recreateTree, recreateTreeFromFields } from './expressions-tree-util';
3+
import { recreateExpression, recreateTree, recreateTreeFromFields } from './expressions-tree-util';
44
import { IgxBooleanFilteringOperand, IgxDateFilteringOperand, IgxDateTimeFilteringOperand, IgxNumberFilteringOperand, IgxStringFilteringOperand, IgxTimeFilteringOperand } from './filtering-condition';
55
import type { EntityType, FieldType } from './grid-types';
66

@@ -477,4 +477,30 @@ describe('Unit testing FilteringUtil', () => {
477477
expect(nestedCondition.condition.name).toBe('greaterThan');
478478
expect(nestedCondition.condition.logic(200, nestedCondition.searchVal)).toBe(true);
479479
});
480+
481+
it('should recreate string expression with correct conditionName', () => {
482+
const fields: FieldType[] = [
483+
{ field: 'Name', dataType: 'string' }
484+
];
485+
486+
// such expression will exist if user has changed the condition OR restore grid state through the IgxGridState directive
487+
const expression: IFilteringExpression = {
488+
fieldName: 'Name',
489+
conditionName: 'contains',
490+
searchVal: 'test',
491+
condition: {
492+
name: 'startsWith',
493+
iconName: 'starts_with',
494+
isUnary: false,
495+
}
496+
};
497+
498+
const result = recreateExpression(expression, fields);
499+
500+
expect(result.condition).toBe(IgxStringFilteringOperand.instance().condition('startsWith'));
501+
expect(result.condition.logic).toBeDefined();
502+
expect(result.conditionName).toBe('startsWith');
503+
expect(result.searchVal).toBe('test');
504+
});
505+
480506
});

projects/igniteui-angular/core/src/data-operations/expressions-tree-util.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ function getFilteringCondition(dataType: string, name: string): IFilteringOperat
125125
*/
126126
function recreateOperatorFromDataType(expression: IFilteringExpression, dataType: string): IFilteringOperation {
127127
if (!expression.condition?.logic) {
128-
return getFilteringCondition(dataType, expression.conditionName || expression.condition?.name);
128+
return getFilteringCondition(dataType, expression.condition?.name || expression.conditionName);
129129
}
130130

131131
return expression.condition;
@@ -138,25 +138,22 @@ function recreateOperatorFromDataType(expression: IFilteringExpression, dataType
138138
* @param fields An array of fields to use for recreating the expression.
139139
* @returns The recreated expression.
140140
*/
141-
function recreateExpression(expression: IFilteringExpression, fields: FieldType[]): IFilteringExpression {
141+
export function recreateExpression(expression: IFilteringExpression, fields: FieldType[]): IFilteringExpression {
142142
const field = fields?.find(f => f.field === expression.fieldName);
143143

144144
if (field && !expression.condition?.logic) {
145145
if (!field.filters) {
146146
expression.condition = recreateOperatorFromDataType(expression, field.dataType);
147147
} else {
148-
expression.condition = field.filters.condition(expression.conditionName || expression.condition?.name);
148+
expression.condition = field.filters.condition(expression.condition?.name || expression.conditionName);
149149
}
150150
}
151151

152152
if (!expression.condition && expression.conditionName) {
153153
throw Error('Wrong `conditionName`, `condition` or `field` provided! It is possible that there is a type mismatch between the condition type and field type.');
154154
}
155155

156-
if (!expression.conditionName) {
157-
expression.conditionName = expression.condition?.name;
158-
}
159-
156+
expression.conditionName = expression.condition?.name;
160157
expression.searchVal = recreateSearchValue(expression.searchVal, field?.dataType);
161158

162159
return expression;

projects/igniteui-angular/grids/core/src/state-base.directive.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ export class IgxGridStateBaseDirective {
203203
dataType: c.dataType,
204204
hasSummary: c.hasSummary,
205205
field: c.field,
206-
width: c.width,
206+
width: ((c as IgxColumnComponent).widthSetByUser || context.currGrid.columnWidthSetByUser) ? c.width : undefined,
207207
header: c.header,
208208
resizable: c.resizable,
209209
searchable: c.searchable,
@@ -226,6 +226,21 @@ export class IgxGridStateBaseDirective {
226226
},
227227
restoreFeatureState: (context: IgxGridStateBaseDirective, state: IColumnState[]): void => {
228228
const newColumns = [];
229+
230+
// Helper to restore column state without auto-persisting widths
231+
const restoreColumnState = (column: IgxColumnComponent | IgxColumnGroupComponent, colState: IColumnState) => {
232+
// Extract width to handle it separately
233+
const width = colState.width;
234+
delete colState.width;
235+
236+
Object.assign(column, colState);
237+
238+
// Only restore width if it was explicitly set by the user (not undefined)
239+
if (width !== undefined) {
240+
column.width = width;
241+
}
242+
};
243+
229244
state.forEach((colState) => {
230245
const hasColumnGroup = colState.columnGroup;
231246
const hasColumnLayouts = colState.columnLayout;
@@ -242,7 +257,9 @@ export class IgxGridStateBaseDirective {
242257
} else {
243258
ref1.children.reset([]);
244259
}
245-
Object.assign(ref1, colState);
260+
261+
restoreColumnState(ref1, colState);
262+
246263
ref1.grid = context.currGrid;
247264
if (colState.parent || colState.parentKey) {
248265
const columnGroup: IgxColumnGroupComponent = newColumns.find(e => e.columnGroup && (e.key ? e.key === colState.parentKey : e.header === ref1.parent));
@@ -259,7 +276,8 @@ export class IgxGridStateBaseDirective {
259276
component.changeDetectorRef.detectChanges();
260277
}
261278

262-
Object.assign(ref, colState);
279+
restoreColumnState(ref, colState);
280+
263281
ref.grid = context.currGrid;
264282
if (colState.parent || colState.parentKey) {
265283
const columnGroup: IgxColumnGroupComponent = newColumns.find(e => e.columnGroup && (e.key ? e.key === colState.parentKey : e.header === ref.parent));

projects/igniteui-angular/grids/core/src/state.directive.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,55 @@ describe('IgxGridState - input properties #grid', () => {
802802
expect(prodIdColumn.colStart).toBe(1);
803803
expect(prodIdColumn.colEnd).toBe(1);
804804
});
805+
806+
it('should preserve column widths when restoring state with all columns hidden', () => {
807+
const fix = TestBed.createComponent(IgxGridStateComponent);
808+
fix.detectChanges();
809+
const grid = fix.componentInstance.grid;
810+
const state = fix.componentInstance.state;
811+
812+
// Store initial column widths - don't hardcode expected values
813+
const initialWidths = grid.columns.map(col => col.width);
814+
815+
// Hide all columns
816+
grid.columns.forEach(col => col.hidden = true);
817+
fix.detectChanges();
818+
819+
// Verify all columns are hidden
820+
expect(grid.columns.every(col => col.hidden)).toBe(true);
821+
822+
// Get and save the state with all columns hidden
823+
const gridState = state.getState(false) as IGridState;
824+
expect(gridState.columns.every(col => col.hidden)).toBe(true);
825+
826+
// Restore the state
827+
state.setState(gridState);
828+
fix.detectChanges();
829+
830+
// Verify all columns are still hidden
831+
expect(grid.columns.every(col => col.hidden)).toBe(true);
832+
833+
// Unhide all columns
834+
grid.columns.forEach(col => col.hidden = false);
835+
fix.detectChanges();
836+
837+
// Verify column widths are preserved and not set to minimum
838+
// The issue was that when all columns were hidden, _columnWidth would be set to "0px"
839+
// and all columns would end up with minimum width when unhidden
840+
grid.columns.forEach((col, index) => {
841+
expect(col.width).toBe(initialWidths[index], `Column ${index} width should be preserved`);
842+
// The calcWidth should be based on the column width or grid default, not forced to 0px
843+
const calcWidth = parseFloat(col.calcWidth);
844+
// Note: some columns may be constrained by minWidth which is expected
845+
// The key is they shouldn't all be the same minimum width
846+
expect(calcWidth).toBeGreaterThan(0, `Column ${index} calcWidth should be greater than 0`);
847+
});
848+
849+
// Verify that not all columns have the same width (which would indicate the bug)
850+
const calcWidths = grid.columns.map(col => parseFloat(col.calcWidth));
851+
const allSameWidth = calcWidths.every(w => w === calcWidths[0]);
852+
expect(allSameWidth).toBe(false, 'Columns should not all have the same width');
853+
});
805854
});
806855

807856
class HelperFunctions {

projects/igniteui-angular/grids/core/src/state.pivotgrid.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ describe('IgxPivotGridState #pivotGrid :', () => {
3434
const jsonString = state.getState(true);
3535
const expectedObj = {
3636
"columns": [
37-
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Bulgaria", "width": "220px", "header": "Bulgaria", "resizable": false, "searchable": true, "selectable": true, "key": "Bulgaria", "columnGroup": false, "disableHiding": false, "disablePinning": false },
38-
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "US", "width": "220px", "header": "US", "resizable": false, "searchable": true, "selectable": true, "key": "US", "columnGroup": false, "disableHiding": false, "disablePinning": false },
39-
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Uruguay", "width": "220px", "header": "Uruguay", "resizable": false, "searchable": true, "selectable": true, "key": "Uruguay", "columnGroup": false, "disableHiding": false, "disablePinning": false },
40-
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "UK", "width": "220px", "header": "UK", "resizable": false, "searchable": true, "selectable": true, "key": "UK", "columnGroup": false, "disableHiding": false, "disablePinning": false },
41-
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Japan", "width": "220px", "header": "Japan", "resizable": false, "searchable": true, "selectable": true, "key": "Japan", "columnGroup": false, "disableHiding": false, "disablePinning": false }
37+
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Bulgaria", "header": "Bulgaria", "resizable": false, "searchable": true, "selectable": true, "key": "Bulgaria", "columnGroup": false, "disableHiding": false, "disablePinning": false },
38+
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "US", "header": "US", "resizable": false, "searchable": true, "selectable": true, "key": "US", "columnGroup": false, "disableHiding": false, "disablePinning": false },
39+
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Uruguay", "header": "Uruguay", "resizable": false, "searchable": true, "selectable": true, "key": "Uruguay", "columnGroup": false, "disableHiding": false, "disablePinning": false },
40+
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "UK", "header": "UK", "resizable": false, "searchable": true, "selectable": true, "key": "UK", "columnGroup": false, "disableHiding": false, "disablePinning": false },
41+
{ "pinned": false, "sortable": true, "filterable": true, "sortingIgnoreCase": true, "filteringIgnoreCase": true, "headerClasses": "", "headerGroupClasses": "", "groupable": false, "hidden": false, "dataType": "number", "hasSummary": false, "field": "Japan", "header": "Japan", "resizable": false, "searchable": true, "selectable": true, "key": "Japan", "columnGroup": false, "disableHiding": false, "disablePinning": false }
4242
],
4343
"filtering": { "filteringOperands": [], "operator": 0, "type": 0 },
4444
"advancedFiltering": {}, "sorting": [], "cellSelection": [], "rowSelection": [], "columnSelection": [],

projects/igniteui-angular/grids/grid/src/column-hiding.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,10 @@ describe('Column Hiding UI #grid', () => {
536536
grid.columnList.forEach((col) => col.hidden = true);
537537
tick(30);
538538
fix.detectChanges();
539+
// Column widths should be preserved when all columns are hidden
540+
// This allows proper width restoration when columns are unhidden
539541
grid.columnList.forEach((col) => {
540-
expect(col.width).toBe('0px');
542+
expect(col.width).not.toBe('0px', 'Column width should not be 0px when hidden');
541543
});
542544
fixEl = fix.nativeElement;
543545
gridEl = grid.nativeElement;

projects/igniteui-angular/grids/grid/src/grid-base.directive.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6796,23 +6796,33 @@ export abstract class IgxGridBaseDirective implements GridType,
67966796
const possibleWidth = this.getPossibleColumnWidth();
67976797
if (possibleWidth === "0px") {
67986798
// all columns - hidden
6799-
this._columnWidth = possibleWidth;
6799+
// Do not update _columnWidth to preserve valid column widths for when columns are unhidden
6800+
// Only update column defaultWidth if _columnWidth is already set and not '0px'
6801+
if (this._columnWidth && this._columnWidth !== '0px') {
6802+
this._updateColumnDefaultWidths();
6803+
}
6804+
this.resetCachedWidths();
6805+
return;
68006806
} else if (this.width !== null) {
68016807
this._columnWidth = Math.max(parseFloat(possibleWidth), this.minColumnWidth) + 'px'
68026808
} else {
68036809
this._columnWidth = this.minColumnWidth + 'px';
68046810
}
68056811
}
6812+
this._updateColumnDefaultWidths();
6813+
this.resetCachedWidths();
6814+
}
6815+
6816+
private _updateColumnDefaultWidths() {
68066817
this._columns.forEach((column: IgxColumnComponent) => {
6807-
if (this.hasColumnLayouts && parseFloat(this._columnWidth)) {
6818+
if (this.hasColumnLayouts) {
68086819
const columnWidthCombined = parseFloat(this._columnWidth) * (column.colEnd ? column.colEnd - column.colStart : 1);
68096820
column.defaultWidth = columnWidthCombined + 'px';
68106821
} else {
68116822
column.defaultWidth = this._columnWidth;
68126823
column.resetCaches();
68136824
}
68146825
});
6815-
this.resetCachedWidths();
68166826
}
68176827

68186828
protected resetNotifyChanges() {

0 commit comments

Comments
 (0)