Skip to content

Commit

Permalink
feat(grid): row selection templating #4998
Browse files Browse the repository at this point in the history
  • Loading branch information
jackofdiamond5 authored and Lipata committed Sep 3, 2019
1 parent 117b450 commit e0af43d
Show file tree
Hide file tree
Showing 22 changed files with 1,123 additions and 75 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ For more information about the theming please read our [documentation](https://w
- `uniqueColumnValuesStrategy` input is added. This property provides a callback for loading unique column values on demand. If this property is provided, the unique values it generates will be used by the Excel Style Filtering (instead of using the unique values from the data that is bound to the grid).
- `igxExcelStyleLoading` directive is added, which can be used to provide a custom loading template for the Excel Style Filtering. If this property is not provided, a default loading template will be used instead.
- introduced new properties `cellSelection` and `rowSelection` which accept GridSelection mode enumeration. Grid selection mode could be none, single or multiple. Also `hideRowSelectors` property is added, which allows you to show and hide row selectors when row selection is enabled.
- introduced functionality for templating row and header selectors - [spec](https://github.com/IgniteUI/igniteui-angular/wiki/Row-Selection-Templating-(Grid-feature))
```html
<igx-grid [data]="data", [rowSelection]="'multiple'" primaryKey="ID">
<igx-column field="Name"></igx-column>
<igx-column field="Age"></igx-column>

<ng-template igxHeadSelector let-headSelector>
<igx-icon>done_all</igx-icon>
</ng-template>
<ng-template igxRowSelector let-rowContext>
<igx-switch [checked]="rowContext.selected"></igx-switch>
</ng-template>
</igx-grid>
```
- `IgxHierarchicalGrid`
- Row Islands now emit child grid events with an additional argument - `owner`, which holds reference to the related child grid component instance.
- `IgxDrag`
Expand Down
6 changes: 6 additions & 0 deletions projects/igniteui-angular/src/lib/core/grid-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,12 @@ export class IgxGridSelectionService {
return this.rowSelection.size > 0 && filteredData && !this.areAllRowSelected();
}

public get filteredSelectedRowIds(): any[] {
return this.isFilteringApplied() ?
this.getRowIDs(this.allData).filter(rowID => this.isRowSelected(rowID)) :
this.getSelectedRows().filter(rowID => !this.isRowDeleted(rowID));
}

public emitRowSelectionEvent(newSelection, added, removed, event?): boolean {
const currSelection = this.getSelectedRows();
if (this.areEqualCollections(currSelection, newSelection)) { return; }
Expand Down
109 changes: 84 additions & 25 deletions projects/igniteui-angular/src/lib/grids/grid-base.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import {
VerticalAlignment,
IgxOverlayService
} from '../services/index';
import { IgxCheckboxComponent } from './../checkbox/checkbox.component';
import { GridBaseAPIService } from './api.service';
import { IgxGridCellComponent } from './cell.component';
import { IColumnVisibilityChangedEventArgs } from './column-hiding-item.directive';
Expand Down Expand Up @@ -89,8 +88,9 @@ import {
import { IgxGridColumnResizerComponent } from './grid-column-resizer.component';
import { IgxGridFilteringRowComponent } from './filtering/grid-filtering-row.component';
import { IgxDragDirective } from '../directives/drag-drop/drag-drop.directive';
import { DeprecateProperty } from '../core/deprecateDecorators';
import { CharSeparatedValueData } from '../services/csv/char-separated-value-data';
import { IgxHeadSelectorDirective, IgxRowSelectorDirective } from './igx-row-selectors.module';
import { DeprecateProperty } from '../core/deprecateDecorators';

const MINIMUM_COLUMN_WIDTH = 136;
const FILTER_ROW_HEIGHT = 50;
Expand Down Expand Up @@ -259,6 +259,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
private _locale = null;
public _destroyed = false;
private overlayIDs = [];

private _hostWidth;
/**
* An accessor that sets the resource strings.
Expand Down Expand Up @@ -1707,9 +1708,51 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
return this.toolbarCustomContentTemplates.first;
}

/**
* @hidden
* @internal
*/
@ContentChildren(IgxGridToolbarCustomContentDirective, { read: IgxGridToolbarCustomContentDirective, descendants: false })
public toolbarCustomContentTemplates: QueryList<IgxGridToolbarCustomContentDirective>;

/**
* @hidden
* @internal
*/
public get headSelectorTemplate(): TemplateRef<IgxHeadSelectorDirective> {
if (this.headSelectorsTemplates && this.headSelectorsTemplates.first) {
return this.headSelectorsTemplates.first.templateRef;
}

return null;
}

/**
* @hidden
* @internal
*/
@ContentChildren(IgxHeadSelectorDirective, { read: IgxHeadSelectorDirective, descendants: false })
public headSelectorsTemplates: QueryList<IgxHeadSelectorDirective>;

/**
* @hidden
* @internal
*/
public get rowSelectorTemplate(): TemplateRef<IgxRowSelectorDirective> {
if (this.rowSelectorsTemplates && this.rowSelectorsTemplates.first) {
return this.rowSelectorsTemplates.first.templateRef;
}

return null;
}

/**
* @hidden
* @internal
*/
@ContentChildren(IgxRowSelectorDirective, { read: IgxRowSelectorDirective, descendants: false })
public rowSelectorsTemplates: QueryList<IgxRowSelectorDirective>;

/**
* @hidden
*/
Expand Down Expand Up @@ -1743,8 +1786,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
/**
* @hidden
*/
@ViewChild('headerCheckboxContainer', { static: false })
public headerCheckboxContainer: ElementRef;
@ViewChild('headerSelectorContainer', { static: false })
public headerSelectorContainer: ElementRef;

/**
* @hidden
Expand All @@ -1758,12 +1801,6 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
@ViewChild('headerGroupContainer', { static: false })
public headerGroupContainer: ElementRef;

/**
* @hidden
*/
@ViewChild('headerCheckbox', { read: IgxCheckboxComponent, static: false })
public headerCheckbox: IgxCheckboxComponent;

/**
* @hidden
*/
Expand Down Expand Up @@ -1841,6 +1878,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
*/
@ViewChild('defaultRowEditTemplate', { read: TemplateRef, static: true })
private defaultRowEditTemplate: TemplateRef<any>;

/**
* @hidden
*/
Expand Down Expand Up @@ -3337,10 +3375,18 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
return totalWidth;
}

get showRowCheckboxes(): boolean {
/**
* @hidden
* @internal
*/
get showRowSelectors(): boolean {
return this.isRowSelectable && this.hasVisibleColumns && !this.hideRowSelectors;
}

/**
* @hidden
* @internal
*/
get showDragIcons(): boolean {
return this.rowDraggable && this.columns.length > this.hiddenColumnsCount;
}
Expand Down Expand Up @@ -4167,7 +4213,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
const pagingHeight = this.getPagingHeight();
const groupAreaHeight = this.getGroupAreaHeight();
const renderedHeight = toolbarHeight + this.theadRow.nativeElement.offsetHeight +
footerHeight + pagingHeight + groupAreaHeight +
footerHeight + pagingHeight + groupAreaHeight +
this.scr.nativeElement.clientHeight;

const computed = this.document.defaultView.getComputedStyle(this.nativeElement).getPropertyValue('height');
Expand Down Expand Up @@ -4476,7 +4522,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
let width = 0;

if (this.isRowSelectable) {
width += this.headerCheckboxContainer ? this.headerCheckboxContainer.nativeElement.getBoundingClientRect().width : 0;
width += this.headerSelectorContainer ? this.headerSelectorContainer.nativeElement.getBoundingClientRect().width : 0;
}
if (this.rowDraggable) {
width += this.headerDragContainer ? this.headerDragContainer.nativeElement.getBoundingClientRect().width : 0;
Expand Down Expand Up @@ -4685,10 +4731,24 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
/**
* @hidden
*/
get headerCheckboxAriaLabel() {
return this._filteringExpressionsTree.filteringOperands.length > 0 ?
this.headerCheckbox && this.selectionService.areAllRowSelected() ? 'Deselect all filtered' : 'Select all filtered' :
this.headerCheckbox && this.selectionService.areAllRowSelected() ? 'Deselect all' : 'Select all';
get headSelectorBaseAriaLabel() {
if (this._filteringExpressionsTree.filteringOperands.length > 0) {
return this.selectionService.areAllRowSelected() ? 'Deselect all filtered' : 'Select all filtered';
}

return this.selectionService.areAllRowSelected() ? 'Deselect all' : 'Select all';
}

/**
* @hidden
* @internal
*/
public get totalRowsCountAfterFilter() {
if (this.data) {
return this.selectionService.allData.length;
}

return 0;
}

/**
Expand Down Expand Up @@ -4875,7 +4935,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
if (col) {
const key = headers ? col.header || col.field : col.field;
record[key] = formatters && col.formatter ? col.formatter(source[row][col.field])
: source[row][col.field];
: source[row][col.field];
}
});
}
Expand All @@ -4890,15 +4950,15 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
protected getSelectableColumnsAt(index) {
if (this.hasColumnLayouts) {
const visibleLayoutColumns = this.visibleColumns
.filter(col => col.columnLayout)
.sort((a, b) => a.visibleIndex - b.visibleIndex);
.filter(col => col.columnLayout)
.sort((a, b) => a.visibleIndex - b.visibleIndex);
const colLayout = visibleLayoutColumns[index];
return colLayout ? colLayout.children.toArray() : [];
} else {
const visibleColumns = this.visibleColumns
.filter(col => !col.columnGroup)
.sort((a, b) => a.visibleIndex - b.visibleIndex);
return [ visibleColumns[index] ];
.filter(col => !col.columnGroup)
.sort((a, b) => a.visibleIndex - b.visibleIndex);
return [visibleColumns[index]];
}
}

Expand All @@ -4913,7 +4973,6 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
return this.extractDataFromSelection(source, formatters, headers);
}


/**
* @hidden
*/
Expand Down Expand Up @@ -4944,7 +5003,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
this.onGridCopy.emit(ev);

if (ev.cancel) {
return;
return;
}

const transformer = new CharSeparatedValueData(ev.data, this.clipboardOptions.separator);
Expand Down
7 changes: 5 additions & 2 deletions projects/igniteui-angular/src/lib/grids/grid-common.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { IgxGridExcelStyleFilteringModule } from './filtering/excel-style/grid.e
import { IgxGridDragSelectDirective } from './drag-select.directive';
import { IgxGridColumnResizerComponent } from './grid-column-resizer.component';
import { IgxRowDragModule } from './row-drag.directive';
import { IgxRowSelectorsModule } from './igx-row-selectors.module';
/**
* @hidden
*/
Expand Down Expand Up @@ -164,7 +165,8 @@ import { IgxRowDragModule } from './row-drag.directive';
IgxFilterCellTemplateDirective,
IgxRowDragModule,
IgxPaginatorModule,
IgxGridFooterComponent
IgxGridFooterComponent,
IgxRowSelectorsModule
],
imports: [
CommonModule,
Expand Down Expand Up @@ -193,7 +195,8 @@ import { IgxRowDragModule } from './row-drag.directive';
IgxGridPipesModule,
IgxGridExcelStyleFilteringModule,
IgxRowDragModule,
IgxPaginatorModule
IgxPaginatorModule,
IgxRowSelectorsModule
],
providers: [
IgxGridSelectionService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import {
SelectionWithScrollsComponent,
SingleRowSelectionComponent,
RowSelectionWithoutPrimaryKeyComponent,
SelectionWithTransactionsComponent
SelectionWithTransactionsComponent,
GridCustomSelectorsComponent
} from '../../test-utils/grid-samples.spec';
import { IgxHierarchicalGridModule } from '../hierarchical-grid/hierarchical-grid.module';
import { GridFunctions, GridSelectionFunctions } from '../../test-utils/grid-functions.spec';
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
import { IgxRowSelectorsModule } from '../igx-row-selectors.module';

const DEBOUNCETIME = 30;

Expand All @@ -31,12 +32,13 @@ describe('IgxGrid - Row Selection #grid', () => {
SelectionWithScrollsComponent,
RowSelectionWithoutPrimaryKeyComponent,
SingleRowSelectionComponent,
SelectionWithTransactionsComponent
SelectionWithTransactionsComponent,
GridCustomSelectorsComponent,
],
imports: [
NoopAnimationsModule,
IgxGridModule,
IgxHierarchicalGridModule
IgxRowSelectorsModule
]
})
.compileComponents();
Expand Down Expand Up @@ -1871,4 +1873,62 @@ describe('IgxGrid - Row Selection #grid', () => {
GridSelectionFunctions.verifyRowSelected(addedRow);
}));
});

describe('Custom selectors', () => {
let fix;
let grid;

beforeEach(fakeAsync(() => {
fix = TestBed.createComponent(GridCustomSelectorsComponent);
fix.detectChanges();
grid = fix.componentInstance.grid;
grid.rowSelection = GridSelectionMode.multiple;
}));

it('Should have the correct properties in the custom row selector template', () => {
const firstRow = grid.getRowByIndex(0);
const firstCheckbox = firstRow.nativeElement.querySelector('.igx-checkbox__composite');
const context = { index: 0, rowID: 'ALFKI', selected: false };
const contextUnselect = { index: 0, rowID: 'ALFKI', selected: true };
spyOn(fix.componentInstance, 'onRowCheckboxClick').and.callThrough();
firstCheckbox.click();
fix.detectChanges();

expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledTimes(1);
expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledWith(new MouseEvent('click'), context);

// Verify correct properties when unselecting a row
firstCheckbox.click();
fix.detectChanges();

expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledTimes(2);
expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledWith(new MouseEvent('click'), contextUnselect);
});

it('Should have the correct properties in the custom row selector header template', () => {
const context = { selectedCount: 0, totalCount: 27 };
const contextUnselect = { selectedCount: 27, totalCount: 27 };
const headerCheckbox = fix.nativeElement.querySelector('.igx-grid__thead').querySelector('.igx-checkbox__composite');
spyOn(fix.componentInstance, 'onHeaderCheckboxClick').and.callThrough();
headerCheckbox.click();
fix.detectChanges();

expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(1);
expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledWith(new MouseEvent('click'), context);

headerCheckbox.click();
fix.detectChanges();

expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(2);
expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledWith(new MouseEvent('click'), contextUnselect);
});

it('Should have correct indices on all pages', () => {
grid.nextPage();
fix.detectChanges();

const firstRootRow = grid.getRowByIndex(0);
expect(firstRootRow.nativeElement.querySelector('.rowNumber').textContent).toEqual('30');
});
});
});
Loading

0 comments on commit e0af43d

Please sign in to comment.