Skip to content

Commit 277862b

Browse files
authored
Merge pull request #5846 from IgniteUI/nrobakova/fix-issue-5837
Update children collection when add or remove column in column group
2 parents 90c5601 + 51237b8 commit 277862b

File tree

2 files changed

+86
-25
lines changed

2 files changed

+86
-25
lines changed

projects/igniteui-angular/src/lib/grids/column.component.ts

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
QueryList,
1010
TemplateRef,
1111
forwardRef,
12+
OnDestroy,
1213
Output,
1314
EventEmitter
1415
} from '@angular/core';
@@ -35,6 +36,8 @@ import { DeprecateProperty } from '../core/deprecateDecorators';
3536
import { MRLColumnSizeInfo, MRLResizeColumnInfo } from '../data-operations/multi-row-layout.interfaces';
3637
import { DisplayDensity } from '../core/displayDensity';
3738
import { notifyChanges } from './watch-changes';
39+
import { Subject } from 'rxjs';
40+
import { takeUntil } from 'rxjs/operators';
3841
import {
3942
IgxCellTemplateDirective,
4043
IgxCellHeaderTemplateDirective,
@@ -56,7 +59,7 @@ import {
5659
selector: 'igx-column',
5760
template: ``
5861
})
59-
export class IgxColumnComponent implements AfterContentInit {
62+
export class IgxColumnComponent implements AfterContentInit, OnDestroy {
6063
/**
6164
* Sets/gets the `field` value.
6265
* ```typescript
@@ -874,13 +877,13 @@ export class IgxColumnComponent implements AfterContentInit {
874877
return false;
875878
}
876879

877-
/**
878-
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
879-
* ```typescript
880-
* let columnLayoutChild = this.column.columnLayoutChild;
881-
* ```
882-
* @memberof IgxColumnComponent
883-
*/
880+
/**
881+
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
882+
* ```typescript
883+
* let columnLayoutChild = this.column.columnLayoutChild;
884+
* ```
885+
* @memberof IgxColumnComponent
886+
*/
884887
get columnLayoutChild() {
885888
return this.parent && this.parent.columnLayout;
886889
}
@@ -1015,6 +1018,11 @@ export class IgxColumnComponent implements AfterContentInit {
10151018
* @memberof IgxColumnComponent
10161019
*/
10171020
children: QueryList<IgxColumnComponent>;
1021+
/**
1022+
* @hidden
1023+
*/
1024+
protected destroy$ = new Subject<boolean>();
1025+
10181026
/**
10191027
*@hidden
10201028
*/
@@ -1198,7 +1206,7 @@ export class IgxColumnComponent implements AfterContentInit {
11981206
if (!col.colStart) {
11991207
return;
12001208
}
1201-
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1209+
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
12021210
const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
12031211
const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
12041212
const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
@@ -1270,8 +1278,8 @@ export class IgxColumnComponent implements AfterContentInit {
12701278
for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
12711279
if (columnSizes[i + j] &&
12721280
((!columnSizes[i].width && columnSizes[i + j].width) ||
1273-
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1274-
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
1281+
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1282+
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
12751283
// If we reach an already defined column that has width and the current doesn't have or
12761284
// if the reached column has bigger colSpan we stop.
12771285
break;
@@ -1319,8 +1327,8 @@ export class IgxColumnComponent implements AfterContentInit {
13191327
}
13201328

13211329
protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
1322-
const res = this.getFilledChildColumnSizes(children);
1323-
return res.join(' ');
1330+
const res = this.getFilledChildColumnSizes(children);
1331+
return res.join(' ');
13241332
}
13251333

13261334
public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
@@ -1334,7 +1342,7 @@ export class IgxColumnComponent implements AfterContentInit {
13341342

13351343
for (let i = 0; i < columnSized.length; i++) {
13361344
if (this.colStart <= i + 1 && i + 1 < colEnd) {
1337-
targets.push({ target: columnSized[i].ref, spanUsed: 1});
1345+
targets.push({ target: columnSized[i].ref, spanUsed: 1 });
13381346
}
13391347
}
13401348

@@ -1414,7 +1422,7 @@ export class IgxColumnComponent implements AfterContentInit {
14141422
grid.resetCaches();
14151423
grid.notifyChanges();
14161424
if (this.columnLayoutChild) {
1417-
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
1425+
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
14181426
}
14191427
this.grid.filteringService.refreshExpressions();
14201428
// this.grid.refreshSearch(true);
@@ -1478,7 +1486,7 @@ export class IgxColumnComponent implements AfterContentInit {
14781486

14791487
grid.notifyChanges();
14801488
if (this.columnLayoutChild) {
1481-
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
1489+
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
14821490
}
14831491
this.grid.filteringService.refreshExpressions();
14841492
// this.grid.refreshSearch(true);
@@ -1678,6 +1686,14 @@ export class IgxColumnComponent implements AfterContentInit {
16781686
* @hidden
16791687
*/
16801688
public populateVisibleIndexes() { }
1689+
1690+
/**
1691+
* @hidden
1692+
*/
1693+
public ngOnDestroy() {
1694+
this.destroy$.next(true);
1695+
this.destroy$.complete();
1696+
}
16811697
}
16821698

16831699

@@ -1687,8 +1703,7 @@ export class IgxColumnComponent implements AfterContentInit {
16871703
selector: 'igx-column-group',
16881704
template: ``
16891705
})
1690-
export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit {
1691-
1706+
export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit, OnDestroy {
16921707
@ContentChildren(IgxColumnComponent, { read: IgxColumnComponent })
16931708
children = new QueryList<IgxColumnComponent>();
16941709
/**
@@ -1832,7 +1847,21 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
18321847
this.children.forEach(child => {
18331848
child.parent = this;
18341849
});
1850+
/*
1851+
TO DO: In Angular 9 this need to be removed, because the @ContentChildren will not return the `parent`
1852+
component in the query list.
1853+
*/
1854+
this.children.changes.pipe(takeUntil(this.destroy$))
1855+
.subscribe((change) => {
1856+
if (change.length > 1 && change.first === this) {
1857+
this.children.reset(this.children.toArray().slice(1));
1858+
this.children.forEach(child => {
1859+
child.parent = this;
1860+
});
1861+
}
1862+
});
18351863
}
1864+
18361865
/**
18371866
* Returns the children columns collection.
18381867
* ```typescript
@@ -1877,7 +1906,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
18771906
return acc;
18781907
}
18791908
if (typeof val.width === 'string' && val.width.indexOf('%') !== -1) {
1880-
isChildrenWidthInPercent = true;
1909+
isChildrenWidthInPercent = true;
18811910
}
18821911
return acc + parseInt(val.width, 10);
18831912
}, 0)}`;
@@ -1898,7 +1927,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
18981927
selector: 'igx-column-layout',
18991928
template: ``
19001929
})
1901-
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit {
1930+
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit, OnDestroy {
19021931
public childrenVisibleIndexes = [];
19031932
/**
19041933
* Gets the width of the column layout.
@@ -1983,7 +2012,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
19832012
this.children.forEach(child => child.hidden = value);
19842013
if (this.grid && this.grid.columns && this.grid.columns.length > 0) {
19852014
// reset indexes in case columns are hidden/shown runtime
1986-
this.grid.columns.filter(x => x.columnGroup).forEach( x => x.populateVisibleIndexes());
2015+
this.grid.columns.filter(x => x.columnGroup).forEach(x => x.populateVisibleIndexes());
19872016
}
19882017
}
19892018

@@ -2022,17 +2051,16 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
20222051
const grid = this.gridAPI.grid;
20232052
const columns = grid && grid.pinnedColumns && grid.unpinnedColumns ? grid.pinnedColumns.concat(grid.unpinnedColumns) : [];
20242053
const orderedCols = columns
2025-
.filter(x => !x.columnGroup && !x.hidden)
2026-
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
2054+
.filter(x => !x.columnGroup && !x.hidden)
2055+
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
20272056
this.children.forEach(child => {
20282057
const rs = child.rowStart || 1;
20292058
let vIndex = 0;
20302059
// filter out all cols with larger rowStart
20312060
const cols = orderedCols.filter(c =>
20322061
!c.columnGroup && (c.rowStart || 1) <= rs);
20332062
vIndex = cols.indexOf(child);
2034-
this.childrenVisibleIndexes.push({column: child, index: vIndex});
2063+
this.childrenVisibleIndexes.push({ column: child, index: vIndex });
20352064
});
20362065
}
2037-
20382066
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,39 @@ describe('IgxGrid - multi-column headers #grid', () => {
15531553
expect(firstColumnGroup.header).toEqual(expectedColumnName);
15541554
expect(expectedColumnListLength).toEqual(columnLength);
15551555
});
1556+
1557+
it('There shouldn\'t be any errors when dynamically removing or adding a column in column group', () => {
1558+
const fixture = TestBed.createComponent(DynamicColGroupsGridComponent);
1559+
fixture.detectChanges();
1560+
1561+
const grid = fixture.componentInstance.grid;
1562+
1563+
expect(grid.columnList.length).toEqual(10);
1564+
1565+
expect(() => {
1566+
// Delete column
1567+
fixture.componentInstance.columnGroups[0].columns.splice(0, 1);
1568+
fixture.detectChanges();
1569+
}).not.toThrow();
1570+
1571+
expect(grid.columnList.length).toEqual(9);
1572+
1573+
expect(() => {
1574+
// Add column
1575+
fixture.componentInstance.columnGroups[0].columns.push({ field: 'Fax', type: 'string' });
1576+
fixture.detectChanges();
1577+
}).not.toThrow();
1578+
1579+
expect(grid.columnList.length).toEqual(10);
1580+
1581+
expect(() => {
1582+
// Update column
1583+
fixture.componentInstance.columnGroups[0].columns[1] = { field: 'City', type: 'string' };
1584+
fixture.detectChanges();
1585+
}).not.toThrow();
1586+
1587+
expect(grid.columnList.length).toEqual(10);
1588+
});
15561589
});
15571590

15581591
@Component({

0 commit comments

Comments
 (0)