Skip to content

Commit ab0315c

Browse files
authored
Merge branch 'master' into bpenkov/date-time-editor
2 parents 889ace2 + 4e67b5f commit ab0315c

32 files changed

+1557
-773
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ All notable changes for each version of this project will be documented in this
1414
### New Features
1515

1616
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`
17+
- Added ability to pin rows to top or bottom depending on the new `pinning` input.
18+
And new API methods `pinRow` and `unpinRow`.
19+
```html
20+
<igx-grid [data]="data" [pinning]="pinningConfiguration"></igx-grid>
21+
```
22+
```typescript
23+
public pinningConfiguration: IPinningConfig = { rows: RowPinningPosition.Bottom };
24+
```
25+
```typescript
26+
this.grid.pinRow(rowID);
27+
```
1728
- Added support for pinning columns on the right. Change the position of pinning using the new `pinning` input.
1829
```html
1930
<igx-grid [data]="data" [pinning]="pinningConfiguration"></igx-grid>

projects/igniteui-angular/src/lib/core/styles/components/navbar/_navbar-theme.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,5 +155,6 @@
155155

156156
%igx-navbar-title {
157157
@include igx-type-style($type-scale, $title);
158+
margin-bottom: 0;
158159
}
159160
}

projects/igniteui-angular/src/lib/grids/api.service.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ export class GridBaseAPIService <T extends IgxGridBaseDirective & GridType> {
8686
}
8787

8888
public get_row_by_key(rowSelector: any): IgxRowDirective<IgxGridBaseDirective & GridType> {
89+
if (!this.grid) {
90+
return null;
91+
}
8992
const primaryKey = this.grid.primaryKey;
9093
if (primaryKey !== undefined && primaryKey !== null) {
9194
return this.grid.dataRowList.find((row) => row.rowData[primaryKey] === rowSelector);

projects/igniteui-angular/src/lib/grids/filtering/base/grid-filtering-row.component.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,14 @@ export class IgxGridFilteringRowComponent implements AfterViewInit {
462462
this.expressionsList[0].expression.searchVal === null &&
463463
this.expressionsList[0].expression.condition.isUnary === false) {
464464
this.filteringService.getExpressions(this.column.field).pop();
465+
466+
this.filter();
465467
} else {
466-
this.expressionsList.forEach((item) => {
467-
if (item.expression.searchVal === null && !item.expression.condition.isUnary) {
468-
this.filteringService.removeExpression(this.column.field, this.expressionsList.indexOf(item));
469-
}
470-
});
468+
const condToRemove = this.expressionsList.filter(ex => ex.expression.searchVal === null && !ex.expression.condition.isUnary);
469+
if (condToRemove && condToRemove.length > 0) {
470+
condToRemove.forEach(c => this.filteringService.removeExpression(this.column.field, this.expressionsList.indexOf(c)));
471+
this.filter();
472+
}
471473
}
472474

473475
this.filteringService.isFilterRowVisible = false;

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

Lines changed: 105 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ import { IgxColumnComponent } from './columns/column.component';
147147
import { IgxColumnGroupComponent } from './columns/column-group.component';
148148
import { IGridSortingStrategy } from '../data-operations/sorting-strategy';
149149
import { IgxRowDragGhostDirective, IgxDragIndicatorIconDirective } from './row-drag.directive';
150+
import { isNumber } from 'util';
150151

151152
const MINIMUM_COLUMN_WIDTH = 136;
152153
const FILTER_ROW_HEIGHT = 50;
@@ -603,6 +604,13 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
603604
this.notifyChanges();
604605
}
605606

607+
/**
608+
* @hidden
609+
* @internal
610+
*/
611+
@Input()
612+
public class = '';
613+
606614
/**
607615
* Gets/Sets the height.
608616
* @example
@@ -632,6 +640,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
632640
get hostWidth() {
633641
return this._width || this._hostWidth;
634642
}
643+
635644
/**
636645
* Gets/Sets the width of the grid.
637646
* @example
@@ -1747,8 +1756,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
17471756
/**
17481757
* @hidden @internal
17491758
*/
1750-
@ViewChild('pinContainer', { static: false })
1751-
public pinContainer: ElementRef;
1759+
@ViewChildren('pinContainer', { read: ElementRef })
1760+
public pinContainers: QueryList<ElementRef>;
17521761

17531762
/**
17541763
* @hidden @internal
@@ -1939,7 +1948,10 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
19391948
*/
19401949
@HostBinding('attr.class')
19411950
get hostClass(): string {
1942-
return this.getComponentDensityClass('igx-grid');
1951+
const classes = [this.getComponentDensityClass('igx-grid')];
1952+
// The custom classes should be at the end.
1953+
classes.push(this.class);
1954+
return classes.join(' ');
19431955
}
19441956

19451957
get bannerClass(): string {
@@ -2410,6 +2422,11 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
24102422
*/
24112423
protected destroy$ = new Subject<any>();
24122424

2425+
protected _filteredSortedPinnedData;
2426+
protected _filteredSortedUnpinnedData;
2427+
protected _filteredPinnedData;
2428+
protected _filteredUnpinnedData;
2429+
24132430
/**
24142431
* @hidden
24152432
*/
@@ -2479,15 +2496,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
24792496
*/
24802497
protected _columnPinning = false;
24812498

2482-
2483-
/**
2484-
* @hidden
2485-
*/
2486-
public get pinnedRecords() {
2487-
return this._pinnedRecords;
2488-
}
2489-
2490-
protected _pinnedRecords = [];
2499+
protected _pinnedRecordIDs = [];
24912500

24922501
/**
24932502
* @hidden
@@ -2652,6 +2661,40 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
26522661
});
26532662
}
26542663

2664+
/**
2665+
* @hidden
2666+
* @internal
2667+
*/
2668+
public isRecordPinned(rec) {
2669+
const id = this.primaryKey ? rec[this.primaryKey] : rec;
2670+
return this._pinnedRecordIDs.indexOf(id) !== -1;
2671+
}
2672+
2673+
/**
2674+
* @hidden
2675+
* @internal
2676+
*/
2677+
public pinRecordIndex(rec) {
2678+
const id = this.primaryKey ? rec[this.primaryKey] : rec;
2679+
return this._pinnedRecordIDs.indexOf(id);
2680+
}
2681+
2682+
/**
2683+
* @hidden
2684+
* @internal
2685+
*/
2686+
public get hasPinnedRecords() {
2687+
return this._pinnedRecordIDs.length > 0;
2688+
}
2689+
2690+
/**
2691+
* @hidden
2692+
* @internal
2693+
*/
2694+
public get pinnedRecordsCount() {
2695+
return this._pinnedRecordIDs.length;
2696+
}
2697+
26552698
private keydownHandler = (event) => {
26562699
const key = event.key.toLowerCase();
26572700
if ((isNavigationKey(key) && event.keyCode !== 32) || key === 'tab' || key === 'pagedown' || key === 'pageup') {
@@ -2798,6 +2841,10 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
27982841
this.endEdit(true);
27992842
this.cdr.markForCheck();
28002843
});
2844+
2845+
this.onRowPinning.subscribe(() => {
2846+
this.summaryService.clearSummaryCache();
2847+
});
28012848
}
28022849

28032850
/**
@@ -2847,6 +2894,17 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
28472894
}
28482895
}
28492896

2897+
public setFilterData(data, pinned: boolean) {
2898+
if (this.hasPinnedRecords && pinned) {
2899+
this._filteredPinnedData = data;
2900+
this.filteredData = [... this._filteredPinnedData, ... this._filteredUnpinnedData];
2901+
} else if (this.hasPinnedRecords && !pinned) {
2902+
this._filteredUnpinnedData = data;
2903+
} else {
2904+
this.filteredData = data;
2905+
}
2906+
}
2907+
28502908
/**
28512909
* @hidden
28522910
* @internal
@@ -2890,6 +2948,22 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
28902948
this.setupColumns();
28912949
}
28922950

2951+
/**
2952+
* @hidden
2953+
* @internal
2954+
*/
2955+
public setFilteredSortedData(data, pinned: boolean) {
2956+
if (this._pinnedRecordIDs.length > 0 && pinned) {
2957+
this._filteredSortedPinnedData = data;
2958+
this.filteredSortedData = this.isRowPinningToTop ? [... this._filteredSortedPinnedData, ... this._filteredSortedUnpinnedData] :
2959+
[... this._filteredSortedUnpinnedData, ... this._filteredSortedPinnedData];
2960+
} else if (this._pinnedRecordIDs.length > 0 && !pinned) {
2961+
this._filteredSortedUnpinnedData = data;
2962+
} else {
2963+
this.filteredSortedData = data;
2964+
}
2965+
}
2966+
28932967
/**
28942968
* @hidden @internal
28952969
*/
@@ -2938,6 +3012,12 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
29383012
vertScrDC.addEventListener('scroll', this.scrollHandler);
29393013
vertScrDC.addEventListener('wheel', () => this.wheelHandler());
29403014

3015+
this.pinContainers.changes.subscribe((c) => {
3016+
if (this.hasPinnedRecords) {
3017+
// on row pin containers change grid sizes should be recalculated.
3018+
this.calculateGridSizes();
3019+
}
3020+
});
29413021
}
29423022

29433023
/**
@@ -3062,6 +3142,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
30623142
public set expansionStates(value) {
30633143
this._expansionStates = new Map<any, boolean>(value);
30643144
this.expansionStatesChange.emit(this._expansionStates);
3145+
this.notifyChanges(true);
30653146
if (this.gridAPI.grid) {
30663147
this.cdr.detectChanges();
30673148
}
@@ -4066,8 +4147,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40664147
* @param index The index at which to insert the row in the pinned collection.
40674148
*/
40684149
public pinRow(rowID: any, index?: number): boolean {
4069-
const rec = this.gridAPI.get_rec_by_id(rowID);
4070-
if (!rec || this.pinnedRecords.indexOf(rec) !== -1 || this.data.indexOf(rec) === -1) {
4150+
if (this._pinnedRecordIDs.indexOf(rowID) !== -1) {
40714151
return false;
40724152
}
40734153
const row = this.gridAPI.get_row_by_key(rowID);
@@ -4080,7 +4160,10 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40804160
};
40814161
this.onRowPinning.emit(eventArgs);
40824162

4083-
this.pinnedRecords.splice(eventArgs.insertAtIndex || this.pinnedRecords.length, 0, rec);
4163+
this.endEdit(true);
4164+
4165+
const insertIndex = isNumber(eventArgs.insertAtIndex) ? eventArgs.insertAtIndex : this._pinnedRecordIDs.length;
4166+
this._pinnedRecordIDs.splice(insertIndex, 0, rowID);
40844167
this._pipeTrigger++;
40854168
if (this.gridAPI.grid) {
40864169
this.notifyChanges(true);
@@ -4098,9 +4181,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40984181
* @param rowID The row id - primaryKey value or the data record instance.
40994182
*/
41004183
public unpinRow(rowID: any) {
4101-
const rec = this.gridAPI.get_rec_by_id(rowID);
4102-
const index = this.pinnedRecords.indexOf(rec);
4103-
if (index === -1 || !rec) {
4184+
const index = this._pinnedRecordIDs.indexOf(rowID);
4185+
if (index === -1) {
41044186
return false;
41054187
}
41064188
const row = this.gridAPI.get_row_by_key(rowID);
@@ -4110,7 +4192,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
41104192
row: row
41114193
};
41124194
this.onRowPinning.emit(eventArgs);
4113-
this.pinnedRecords.splice(index, 1);
4195+
this.endEdit(true);
4196+
this._pinnedRecordIDs.splice(index, 1);
41144197
this._pipeTrigger++;
41154198
if (this.gridAPI.grid) {
41164199
this.cdr.detectChanges();
@@ -4120,8 +4203,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
41204203
}
41214204

41224205
get pinnedRowHeight() {
4123-
const containerHeight = this.pinContainer ? this.pinContainer.nativeElement.offsetHeight : 0;
4124-
return this.pinnedRecords.length > 0 ? containerHeight : 0;
4206+
const pinContainer = this.pinContainers && this.pinContainers.length > 0 ? this.pinContainers.first : null;
4207+
const containerHeight = pinContainer ? pinContainer.nativeElement.offsetHeight : 0;
4208+
return this.hasPinnedRecords ? containerHeight : 0;
41254209
}
41264210

41274211
get totalHeight() {

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { DefaultSortingStrategy } from '../../data-operations/sorting-strategy';
1313
import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition';
1414
import { configureTestSuite } from '../../test-utils/configure-suite';
1515
import { IgxGridHeaderComponent } from '../headers/grid-header.component';
16+
import { GridSummaryFunctions } from '../../test-utils/grid-functions.spec';
1617

1718
const GRID_COL_THEAD_TITLE_CLASS = 'igx-grid__th-title';
1819
const GRID_COL_GROUP_THEAD_TITLE_CLASS = 'igx-grid__thead-title';
@@ -179,6 +180,8 @@ describe('IgxGrid - multi-column headers #grid', () => {
179180
expect(getColGroup(grid, 'General Information').hidden).toEqual(false);
180181
}));
181182

183+
184+
182185
it('Width should be correct. Column group with column. No width.', fakeAsync(/** height/width setter rAF */() => {
183186
const fixture = TestBed.createComponent(OneGroupOneColGridComponent);
184187
fixture.detectChanges();
@@ -1215,6 +1218,28 @@ describe('IgxGrid - multi-column headers #grid', () => {
12151218
expect(grid.getCellByColumn(4, 'Country').value).toEqual('Sweden');
12161219
}));
12171220

1221+
it('summaries - verify summaries when there are grouped columns', fakeAsync(() => {
1222+
const fixture = TestBed.createComponent(ColumnGroupFourLevelTestComponent);
1223+
fixture.detectChanges();
1224+
const grid = fixture.componentInstance.grid;
1225+
const allColumns = grid.columnList;
1226+
allColumns.forEach((col) => {
1227+
if (!col.columnGroup) {
1228+
col.hasSummary = true;
1229+
}
1230+
});
1231+
fixture.detectChanges();
1232+
1233+
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
1234+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, ['Count'], ['27']);
1235+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['27']);
1236+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['27']);
1237+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count'], ['27']);
1238+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Count'], ['27']);
1239+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 5, ['Count'], ['27']);
1240+
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 6, ['Count'], ['27']);
1241+
}));
1242+
12181243
it('filtering - filter a grouped column', fakeAsync(() => {
12191244
const fixture = TestBed.createComponent(ColumnGroupFourLevelTestComponent);
12201245
fixture.detectChanges();
@@ -1275,6 +1300,7 @@ describe('IgxGrid - multi-column headers #grid', () => {
12751300
}));
12761301

12771302

1303+
12781304
it('grouping - verify grouping when there are grouped columns', fakeAsync(/** height/width setter rAF */() => {
12791305
const fixture = TestBed.createComponent(ColumnGroupGroupingTestComponent);
12801306
fixture.detectChanges();

projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,23 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => {
19691969
const activeFilterIcon = header.nativeElement.querySelector('.igx-excel-filter__icon--filtered');
19701970
expect(activeFilterIcon).toBeDefined('no active filter icon was found');
19711971
}));
1972+
1973+
it('Should clear non-unary conditions with null searchVal when close', fakeAsync(() => {
1974+
GridFunctions.clickFilterCellChip(fix, 'ProductName');
1975+
fix.detectChanges();
1976+
1977+
GridFunctions.openFilterDD(fix.debugElement);
1978+
const dropdownList = fix.debugElement.query(By.css('div.igx-drop-down__list.igx-toggle'));
1979+
GridFunctions.selectFilteringCondition('Empty', dropdownList);
1980+
fix.detectChanges();
1981+
GridFunctions.openFilterDD(fix.debugElement);
1982+
GridFunctions.selectFilteringCondition('Contains', dropdownList);
1983+
fix.detectChanges();
1984+
GridFunctions.closeFilterRow(fix);
1985+
1986+
const headerChip = GridFunctions.getFilterChipsForColumn('ProductName', fix);
1987+
expect(headerChip.length).toBe(1);
1988+
}));
19721989
});
19731990

19741991
describe('Integration scenarios', () => {

0 commit comments

Comments
 (0)