Skip to content
78 changes: 53 additions & 25 deletions projects/igniteui-angular/src/lib/grids/column.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
QueryList,
TemplateRef,
forwardRef,
OnDestroy,
Output,
EventEmitter
} from '@angular/core';
Expand All @@ -35,6 +36,8 @@ import { DeprecateProperty } from '../core/deprecateDecorators';
import { MRLColumnSizeInfo, MRLResizeColumnInfo } from '../data-operations/multi-row-layout.interfaces';
import { DisplayDensity } from '../core/displayDensity';
import { notifyChanges } from './watch-changes';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import {
IgxCellTemplateDirective,
IgxCellHeaderTemplateDirective,
Expand All @@ -56,7 +59,7 @@ import {
selector: 'igx-column',
template: ``
})
export class IgxColumnComponent implements AfterContentInit {
export class IgxColumnComponent implements AfterContentInit, OnDestroy {
/**
* Sets/gets the `field` value.
* ```typescript
Expand Down Expand Up @@ -874,13 +877,13 @@ export class IgxColumnComponent implements AfterContentInit {
return false;
}

/**
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
* ```typescript
* let columnLayoutChild = this.column.columnLayoutChild;
* ```
* @memberof IgxColumnComponent
*/
/**
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
* ```typescript
* let columnLayoutChild = this.column.columnLayoutChild;
* ```
* @memberof IgxColumnComponent
*/
get columnLayoutChild() {
return this.parent && this.parent.columnLayout;
}
Expand Down Expand Up @@ -1015,6 +1018,11 @@ export class IgxColumnComponent implements AfterContentInit {
* @memberof IgxColumnComponent
*/
children: QueryList<IgxColumnComponent>;
/**
* @hidden
*/
protected destroy$ = new Subject<boolean>();

/**
*@hidden
*/
Expand Down Expand Up @@ -1198,7 +1206,7 @@ export class IgxColumnComponent implements AfterContentInit {
if (!col.colStart) {
return;
}
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
Expand Down Expand Up @@ -1270,8 +1278,8 @@ export class IgxColumnComponent implements AfterContentInit {
for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
if (columnSizes[i + j] &&
((!columnSizes[i].width && columnSizes[i + j].width) ||
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
// If we reach an already defined column that has width and the current doesn't have or
// if the reached column has bigger colSpan we stop.
break;
Expand Down Expand Up @@ -1319,8 +1327,8 @@ export class IgxColumnComponent implements AfterContentInit {
}

protected getColumnSizesString(children: QueryList<IgxColumnComponent>): string {
const res = this.getFilledChildColumnSizes(children);
return res.join(' ');
const res = this.getFilledChildColumnSizes(children);
return res.join(' ');
}

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

for (let i = 0; i < columnSized.length; i++) {
if (this.colStart <= i + 1 && i + 1 < colEnd) {
targets.push({ target: columnSized[i].ref, spanUsed: 1});
targets.push({ target: columnSized[i].ref, spanUsed: 1 });
}
}

Expand Down Expand Up @@ -1414,7 +1422,7 @@ export class IgxColumnComponent implements AfterContentInit {
grid.resetCaches();
grid.notifyChanges();
if (this.columnLayoutChild) {
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
}
this.grid.filteringService.refreshExpressions();
// this.grid.refreshSearch(true);
Expand Down Expand Up @@ -1478,7 +1486,7 @@ export class IgxColumnComponent implements AfterContentInit {

grid.notifyChanges();
if (this.columnLayoutChild) {
this.grid.columns.filter(x => x.columnLayout).forEach( x => x.populateVisibleIndexes());
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
}
this.grid.filteringService.refreshExpressions();
// this.grid.refreshSearch(true);
Expand Down Expand Up @@ -1678,6 +1686,14 @@ export class IgxColumnComponent implements AfterContentInit {
* @hidden
*/
public populateVisibleIndexes() { }

/**
* @hidden
*/
public ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
}


Expand All @@ -1687,8 +1703,7 @@ export class IgxColumnComponent implements AfterContentInit {
selector: 'igx-column-group',
template: ``
})
export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit {

export class IgxColumnGroupComponent extends IgxColumnComponent implements AfterContentInit, OnDestroy {
@ContentChildren(IgxColumnComponent, { read: IgxColumnComponent })
children = new QueryList<IgxColumnComponent>();
/**
Expand Down Expand Up @@ -1832,7 +1847,21 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
this.children.forEach(child => {
child.parent = this;
});
/*
TO DO: In Angular 9 this need to be removed, because the @ContentChildren will not return the `parent`
component in the query list.
*/
this.children.changes.pipe(takeUntil(this.destroy$))
.subscribe((change) => {
if (change.length > 1 && change.first === this) {
this.children.reset(this.children.toArray().slice(1));
this.children.forEach(child => {
child.parent = this;
});
}
});
}

/**
* Returns the children columns collection.
* ```typescript
Expand Down Expand Up @@ -1877,7 +1906,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
return acc;
}
if (typeof val.width === 'string' && val.width.indexOf('%') !== -1) {
isChildrenWidthInPercent = true;
isChildrenWidthInPercent = true;
}
return acc + parseInt(val.width, 10);
}, 0)}`;
Expand All @@ -1898,7 +1927,7 @@ export class IgxColumnGroupComponent extends IgxColumnComponent implements After
selector: 'igx-column-layout',
template: ``
})
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit {
export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements AfterContentInit, OnDestroy {
public childrenVisibleIndexes = [];
/**
* Gets the width of the column layout.
Expand Down Expand Up @@ -1983,7 +2012,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
this.children.forEach(child => child.hidden = value);
if (this.grid && this.grid.columns && this.grid.columns.length > 0) {
// reset indexes in case columns are hidden/shown runtime
this.grid.columns.filter(x => x.columnGroup).forEach( x => x.populateVisibleIndexes());
this.grid.columns.filter(x => x.columnGroup).forEach(x => x.populateVisibleIndexes());
}
}

Expand Down Expand Up @@ -2022,17 +2051,16 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements
const grid = this.gridAPI.grid;
const columns = grid && grid.pinnedColumns && grid.unpinnedColumns ? grid.pinnedColumns.concat(grid.unpinnedColumns) : [];
const orderedCols = columns
.filter(x => !x.columnGroup && !x.hidden)
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
.filter(x => !x.columnGroup && !x.hidden)
.sort((a, b) => a.rowStart - b.rowStart || columns.indexOf(a.parent) - columns.indexOf(b.parent) || a.colStart - b.colStart);
this.children.forEach(child => {
const rs = child.rowStart || 1;
let vIndex = 0;
// filter out all cols with larger rowStart
const cols = orderedCols.filter(c =>
!c.columnGroup && (c.rowStart || 1) <= rs);
vIndex = cols.indexOf(child);
this.childrenVisibleIndexes.push({column: child, index: vIndex});
this.childrenVisibleIndexes.push({ column: child, index: vIndex });
});
}

}
33 changes: 33 additions & 0 deletions projects/igniteui-angular/src/lib/grids/grid/column-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,39 @@ describe('IgxGrid - multi-column headers #grid', () => {
expect(firstColumnGroup.header).toEqual(expectedColumnName);
expect(expectedColumnListLength).toEqual(columnLength);
});

it('There shouldn\'t be any errors when dynamically removing or adding a column in column group', () => {
const fixture = TestBed.createComponent(DynamicColGroupsGridComponent);
fixture.detectChanges();

const grid = fixture.componentInstance.grid;

expect(grid.columnList.length).toEqual(10);

expect(() => {
// Delete column
fixture.componentInstance.columnGroups[0].columns.splice(0, 1);
fixture.detectChanges();
}).not.toThrow();

expect(grid.columnList.length).toEqual(9);

expect(() => {
// Add column
fixture.componentInstance.columnGroups[0].columns.push({ field: 'Fax', type: 'string' });
fixture.detectChanges();
}).not.toThrow();

expect(grid.columnList.length).toEqual(10);

expect(() => {
// Update column
fixture.componentInstance.columnGroups[0].columns[1] = { field: 'City', type: 'string' };
fixture.detectChanges();
}).not.toThrow();

expect(grid.columnList.length).toEqual(10);
});
});

@Component({
Expand Down