Skip to content

Commit 5756c25

Browse files
authored
Merge pull request #5850 from IgniteUI/nrobakova/fix-issue-5837-81
Update children collection when add or remove column in column group
2 parents 78a519b + 7587920 commit 5756c25

File tree

2 files changed

+84
-24
lines changed

2 files changed

+84
-24
lines changed

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

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
QueryList,
1010
TemplateRef,
1111
forwardRef,
12-
AfterViewInit
12+
OnDestroy
1313
} from '@angular/core';
1414
import { DataType } from '../data-operations/data-util';
1515
import { GridBaseAPIService } from './api.service';
@@ -39,6 +39,8 @@ import { IgxGridHeaderGroupComponent } from './grid-header-group.component';
3939
import { DeprecateProperty } from '../core/deprecateDecorators';
4040
import { MRLColumnSizeInfo, MRLResizeColumnInfo } from '../data-operations/multi-row-layout.interfaces';
4141
import { DisplayDensity } from '../core/displayDensity';
42+
import { Subject } from 'rxjs';
43+
import { takeUntil } from 'rxjs/operators';
4244

4345
/**
4446
* **Ignite UI for Angular Column** -
@@ -54,7 +56,7 @@ import { DisplayDensity } from '../core/displayDensity';
5456
selector: 'igx-column',
5557
template: ``
5658
})
57-
export class IgxColumnComponent implements AfterContentInit {
59+
export class IgxColumnComponent implements AfterContentInit, OnDestroy {
5860
private _filterable = true;
5961
private _groupable = false;
6062
/**
@@ -879,13 +881,13 @@ export class IgxColumnComponent implements AfterContentInit {
879881
return false;
880882
}
881883

882-
/**
883-
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
884-
* ```typescript
885-
* let columnLayoutChild = this.column.columnLayoutChild;
886-
* ```
887-
* @memberof IgxColumnComponent
888-
*/
884+
/**
885+
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
886+
* ```typescript
887+
* let columnLayoutChild = this.column.columnLayoutChild;
888+
* ```
889+
* @memberof IgxColumnComponent
890+
*/
889891
get columnLayoutChild() {
890892
return this.parent && this.parent.columnLayout;
891893
}
@@ -1020,6 +1022,10 @@ export class IgxColumnComponent implements AfterContentInit {
10201022
* @memberof IgxColumnComponent
10211023
*/
10221024
children: QueryList<IgxColumnComponent>;
1025+
/**
1026+
* @hidden
1027+
*/
1028+
protected destroy$ = new Subject<boolean>();
10231029
/**
10241030
*@hidden
10251031
*/
@@ -1207,7 +1213,7 @@ export class IgxColumnComponent implements AfterContentInit {
12071213
if (!col.colStart) {
12081214
return;
12091215
}
1210-
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
1216+
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
12111217
const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
12121218
const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
12131219
const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
@@ -1279,8 +1285,8 @@ export class IgxColumnComponent implements AfterContentInit {
12791285
for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
12801286
if (columnSizes[i + j] &&
12811287
((!columnSizes[i].width && columnSizes[i + j].width) ||
1282-
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1283-
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
1288+
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
1289+
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
12841290
// If we reach an already defined column that has width and the current doesn't have or
12851291
// if the reached column has bigger colSpan we stop.
12861292
break;
@@ -1328,8 +1334,8 @@ export class IgxColumnComponent implements AfterContentInit {
13281334
}
13291335

13301336
protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
1331-
const res = this.getFilledChildColumnSizes(children);
1332-
return res.join(' ');
1337+
const res = this.getFilledChildColumnSizes(children);
1338+
return res.join(' ');
13331339
}
13341340

13351341
public getResizableColUnderEnd(): MRLResizeColumnInfo[] {
@@ -1343,7 +1349,7 @@ export class IgxColumnComponent implements AfterContentInit {
13431349

13441350
for (let i = 0; i < columnSized.length; i++) {
13451351
if (this.colStart <= i + 1 && i + 1 < colEnd) {
1346-
targets.push({ target: columnSized[i].ref, spanUsed: 1});
1352+
targets.push({ target: columnSized[i].ref, spanUsed: 1 });
13471353
}
13481354
}
13491355

@@ -1422,7 +1428,7 @@ export class IgxColumnComponent implements AfterContentInit {
14221428
grid.resetCaches();
14231429
grid.cdr.detectChanges();
14241430
if (this.columnLayoutChild) {
1425-
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
1431+
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
14261432
}
14271433
this.grid.filteringService.refreshExpressions();
14281434
this.grid.refreshSearch(true);
@@ -1485,7 +1491,7 @@ export class IgxColumnComponent implements AfterContentInit {
14851491

14861492
grid.cdr.detectChanges();
14871493
if (this.columnLayoutChild) {
1488-
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
1494+
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
14891495
}
14901496
this.grid.filteringService.refreshExpressions();
14911497
this.grid.refreshSearch(true);
@@ -1695,6 +1701,14 @@ export class IgxColumnComponent implements AfterContentInit {
16951701
* @hidden
16961702
*/
16971703
public populateVisibleIndexes() { }
1704+
1705+
/**
1706+
* @hidden
1707+
*/
1708+
public ngOnDestroy() {
1709+
this.destroy$.next(true);
1710+
this.destroy$.complete();
1711+
}
16981712
}
16991713

17001714

@@ -1704,7 +1718,7 @@ export class IgxColumnComponent implements AfterContentInit {
17041718
selector: 'igx-column-group',
17051719
template: ``
17061720
})
1707-
export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit {
1721+
export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit, OnDestroy {
17081722

17091723
@ContentChildren(IgxColumnComponent, { read: IgxColumnComponent })
17101724
children = new QueryList<IgxColumnComponent>();
@@ -1836,6 +1850,19 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
18361850
this.children.forEach(child => {
18371851
child.parent = this;
18381852
});
1853+
/*
1854+
TO DO: In Angular 9 this need to be removed, because the @ContentChildren will not return the `parent`
1855+
component in the query list.
1856+
*/
1857+
this.children.changes.pipe(takeUntil(this.destroy$))
1858+
.subscribe((change) => {
1859+
if (change.length > 1 && change.first === this) {
1860+
this.children.reset(this.children.toArray().slice(1));
1861+
this.children.forEach(child => {
1862+
child.parent = this;
1863+
});
1864+
}
1865+
});
18391866
}
18401867
/**
18411868
* Returns the children columns collection.
@@ -1881,7 +1908,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
18811908
return acc;
18821909
}
18831910
if (typeof val.width === 'string' && val.width.indexOf('%') !== -1) {
1884-
isChildrenWidthInPercent = true;
1911+
isChildrenWidthInPercent = true;
18851912
}
18861913
return acc + parseInt(val.width, 10);
18871914
}, 0)}`;
@@ -1902,7 +1929,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
19021929
selector: 'igx-column-layout',
19031930
template: ``
19041931
})
1905-
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit {
1932+
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit, OnDestroy {
19061933
public childrenVisibleIndexes = [];
19071934
/**
19081935
* Gets the width of the column layout.
@@ -1987,7 +2014,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
19872014
this.children.forEach(child => child.hidden = value);
19882015
if (this.grid && this.grid.columns && this.grid.columns.length > 0) {
19892016
// reset indexes in case columns are hidden/shown runtime
1990-
this.grid.columns.filter(x => x.columnGroup).forEach( x => x.populateVisibleIndexes());
2017+
this.grid.columns.filter(x => x.columnGroup).forEach(x => x.populateVisibleIndexes());
19912018
}
19922019
}
19932020

@@ -2026,16 +2053,16 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
20262053
const grid = this.gridAPI.grid;
20272054
const columns = grid && grid.pinnedColumns && grid.unpinnedColumns ? grid.pinnedColumns.concat(grid.unpinnedColumns) : [];
20282055
const orderedCols = columns
2029-
.filter(x => !x.columnGroup && !x.hidden)
2030-
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
2056+
.filter(x => !x.columnGroup && !x.hidden)
2057+
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
20312058
this.children.forEach(child => {
20322059
const rs = child.rowStart || 1;
20332060
let vIndex = 0;
20342061
// filter out all cols with larger rowStart
20352062
const cols = orderedCols.filter(c =>
20362063
!c.columnGroup && (c.rowStart || 1) <= rs);
20372064
vIndex = cols.indexOf(child);
2038-
this.childrenVisibleIndexes.push({column: child, index: vIndex});
2065+
this.childrenVisibleIndexes.push({ column: child, index: vIndex });
20392066
});
20402067
}
20412068

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
@@ -1452,6 +1452,39 @@ describe('IgxGrid - multi-column headers', () => {
14521452
expect(firstColumnGroup.header).toEqual(expectedColumnName);
14531453
expect(expectedColumnListLength).toEqual(columnLength);
14541454
});
1455+
1456+
it('There shouldn\'t be any errors when dynamically removing or adding a column in column group', () => {
1457+
const fixture = TestBed.createComponent(DynamicColGroupsGridComponent);
1458+
fixture.detectChanges();
1459+
1460+
const grid = fixture.componentInstance.grid;
1461+
1462+
expect(grid.columnList.length).toEqual(10);
1463+
1464+
expect(() => {
1465+
// Delete column
1466+
fixture.componentInstance.columnGroups[0].columns.splice(0, 1);
1467+
fixture.detectChanges();
1468+
}).not.toThrow();
1469+
1470+
expect(grid.columnList.length).toEqual(9);
1471+
1472+
expect(() => {
1473+
// Add column
1474+
fixture.componentInstance.columnGroups[0].columns.push({ field: 'Fax', type: 'string' });
1475+
fixture.detectChanges();
1476+
}).not.toThrow();
1477+
1478+
expect(grid.columnList.length).toEqual(10);
1479+
1480+
expect(() => {
1481+
// Update column
1482+
fixture.componentInstance.columnGroups[0].columns[1] = { field: 'City', type: 'string' };
1483+
fixture.detectChanges();
1484+
}).not.toThrow();
1485+
1486+
expect(grid.columnList.length).toEqual(10);
1487+
});
14551488
});
14561489

14571490
@Component({

0 commit comments

Comments
 (0)