Skip to content

Commit

Permalink
feat(grid): add grid row-selection templating #4998
Browse files Browse the repository at this point in the history
  • Loading branch information
jackofdiamond5 committed Jul 31, 2019
1 parent 39b9431 commit 3c8c632
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 63 deletions.
2 changes: 1 addition & 1 deletion projects/igniteui-angular/src/lib/grids/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ export class GridBaseAPIService <T extends IgxGridBaseComponent & IGridDataBinda
if (grid.rowSelectable && grid.selection.is_item_selected(grid.id, rowId)) {
grid.deselectRows([rowId]);
} else {
grid.checkHeaderCheckboxStatus();
grid.calculateRowSelectionStatus();
}

this.deleteRowFromData(rowId, index);
Expand Down
125 changes: 79 additions & 46 deletions projects/igniteui-angular/src/lib/grids/grid-base.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ import {
} from './filtering/excel-style/grid.excel-style-filtering.component';
import { IgxGridColumnResizerComponent } from './grid-column-resizer.component';
import { IgxGridFilteringRowComponent } from './filtering/grid-filtering-row.component';
import { IgxDragIndicatorIconDirective } from './row-drag.directive';
import { IgxDragDirective } from '../directives/dragdrop/dragdrop.directive';
import { DeprecateProperty } from '../core/deprecateDecorators';
import { CharSeparatedValueData } from '../services/csv/char-separated-value-data';
Expand Down Expand Up @@ -241,6 +240,12 @@ export enum GridKeydownTargetType {
hierarchicalRow = 'hierarchicalRow'
}

export enum HeadSelectorStatus {
checked = 'checked',
unchecked = 'unchecked',
indeterminate = 'indeterminate'
}

export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
OnInit, OnChanges, OnDestroy, AfterContentInit, AfterViewInit {
private _scrollWidth: number;
Expand All @@ -257,7 +262,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
private _locale = null;
private _observer: MutationObserver;
protected _destroyed = false;
protected _headSelectorStatus: HeadSelectorStatus;
private overlayIDs = [];
public rowSelected = false;

/**
* An accessor that sets the resource strings.
* By default it uses EN resources.
Expand Down Expand Up @@ -1749,8 +1757,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 @@ -1767,8 +1775,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
/**
* @hidden
*/
@ViewChild('headerCheckbox', { read: IgxCheckboxComponent, static: false })
public headerCheckbox: IgxCheckboxComponent;
@ViewChild(IgxCheckboxComponent, { read: IgxCheckboxComponent, static: false })
public headSelectorBaseTemplate: IgxCheckboxComponent;

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

/**
* @hidden
*/
Expand Down Expand Up @@ -3312,7 +3321,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
return totalWidth;
}

get showRowCheckboxes(): boolean {
get showRowSelectors(): boolean {
return this.rowSelectable && this.columns.length > this.hiddenColumnsCount;
}

Expand Down Expand Up @@ -4175,8 +4184,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
parseInt(this.document.defaultView.getComputedStyle(this.nativeElement).getPropertyValue('width'), 10);
}

if (this.showRowCheckboxes) {
computedWidth -= this.headerCheckboxContainer ? this.headerCheckboxContainer.nativeElement.offsetWidth : 0;
if (this.showRowSelectors) {
computedWidth -= this.headerSelectorContainer ? this.headerSelectorContainer.nativeElement.offsetWidth : 0;
}

const visibleChildColumns = this.visibleColumns.filter(c => !c.columnGroup);
Expand Down Expand Up @@ -4349,8 +4358,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
public getFeatureColumnsWidth() {
let width = 0;

if (this.headerCheckboxContainer) {
width += this.headerCheckboxContainer.nativeElement.getBoundingClientRect().width;
if (this.headerSelectorContainer) {
width += this.headerSelectorContainer.nativeElement.getBoundingClientRect().width;
}
if (this.headerDragContainer) {
width += this.headerDragContainer.nativeElement.getBoundingClientRect().width;
Expand Down Expand Up @@ -4552,48 +4561,72 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
/**
* @hidden
*/
public onHeaderCheckboxClick(event, filteredData) {
this.allRowsSelected = event.checked;
const newSelection =
event.checked ?
filteredData ?
this.selection.add_items(this.id, this.selection.get_all_ids(filteredData, this.primaryKey)) :
this.selection.get_all_ids(this.gridAPI.get_all_data(true), this.primaryKey) :
filteredData ?
this.selection.delete_items(this.id, this.selection.get_all_ids(filteredData, this.primaryKey)) :
this.selection.get_empty();
this.triggerRowSelectionChange(newSelection, null, event, event.checked);
this.checkHeaderCheckboxStatus(event.checked);
public onHeadSelectorClick(event, filteredData) {
this.rowSelected = !this.rowSelected;
this.allRowsSelected = this.rowSelected;
let newSelection;
if (this.rowSelected) {
newSelection = filteredData ?
this.selection.add_items(this.id, this.selection.get_all_ids(filteredData, this.primaryKey)) :
this.selection.get_all_ids(this.gridAPI.get_all_data(true), this.primaryKey);
} else {
newSelection = filteredData ?
this.selection.delete_items(this.id, this.selection.get_all_ids(filteredData, this.primaryKey)) :
this.selection.get_empty();
}

this.triggerRowSelectionChange(newSelection, null, event, this.rowSelected);
this.calculateRowSelectionStatus(this.rowSelected);
}

/**
* @hidden
*/
get headerCheckboxAriaLabel() {
return this._filteringExpressionsTree.filteringOperands.length > 0 ?
this.headerCheckbox && this.headerCheckbox.checked ? 'Deselect all filtered' : 'Select all filtered' :
this.headerCheckbox && this.headerCheckbox.checked ? 'Deselect all' : 'Select all';
this.headSelectorBaseTemplate && this.headSelectorBaseTemplate.checked ? 'Deselect all filtered' : 'Select all filtered' :
this.headSelectorBaseTemplate && this.headSelectorBaseTemplate.checked ? 'Deselect all' : 'Select all';
}

/**
* @hidden
*/
public checkHeaderCheckboxStatus(headerStatus?: boolean) {
public calculateRowSelectionStatus(
headerStatus?: boolean): void {
const filteredData = this.filteringService.filteredData;
const dataLength = filteredData ? filteredData.length : this.dataLength;
this.allRowsSelected = this.selection.are_all_selected(this.id, dataLength);
const areNoneSelected = this.selection.are_none_selected(this.id);
if (headerStatus === undefined) {
const filteredData = this.filteringService.filteredData;
const dataLength = filteredData ? filteredData.length : this.dataLength;
this.allRowsSelected = this.selection.are_all_selected(this.id, dataLength);
if (this.headerCheckbox) {
this.headerCheckbox.indeterminate = !this.allRowsSelected && !this.selection.are_none_selected(this.id);
if (!this.headerCheckbox.indeterminate) {
this.headerCheckbox.checked =
this.allRowsSelected;
}
if (this.allRowsSelected) {
this.headSelectorStatus = HeadSelectorStatus.checked;
} else if (areNoneSelected) {
this.headSelectorStatus = HeadSelectorStatus.unchecked;
} else {
this.headSelectorStatus = HeadSelectorStatus.indeterminate;
}
} else {
this.headSelectorStatus = headerStatus ?
HeadSelectorStatus.checked : HeadSelectorStatus.unchecked;
}
if (this.headSelectorBaseTemplate) {
this.headSelectorBaseTemplate.indeterminate = !this.allRowsSelected && !areNoneSelected;
if (!this.headSelectorBaseTemplate.indeterminate) {
this.headSelectorBaseTemplate.checked =
this.allRowsSelected;
}
this.cdr.markForCheck();
} else if (this.headerCheckbox) {
this.headerCheckbox.checked = headerStatus !== undefined ? headerStatus : false;
}

this.cdr.markForCheck();
}

protected get headSelectorStatus(): HeadSelectorStatus {
return this._headSelectorStatus;
}

@Input()
protected set headSelectorStatus(v: HeadSelectorStatus) {
this._headSelectorStatus = v;
}

/**
Expand Down Expand Up @@ -4627,31 +4660,31 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
*/
public updateHeaderCheckboxStatusOnFilter(data) {
if (!data) {
this.checkHeaderCheckboxStatus();
this.calculateRowSelectionStatus();
return;
}
switch (this.filteredItemsStatus(this.id, data, this.primaryKey)) {
case 'allSelected': {
if (!this.allRowsSelected) {
this.allRowsSelected = true;
}
if (this.headerCheckbox.indeterminate) {
this.headerCheckbox.indeterminate = false;
if (this.headSelectorBaseTemplate.indeterminate) {
this.headSelectorBaseTemplate.indeterminate = false;
}
break;
}
case 'noneSelected': {
if (this.allRowsSelected) {
this.allRowsSelected = false;
}
if (this.headerCheckbox.indeterminate) {
this.headerCheckbox.indeterminate = false;
if (this.headSelectorBaseTemplate.indeterminate) {
this.headSelectorBaseTemplate.indeterminate = false;
}
break;
}
default: {
if (!this.headerCheckbox.indeterminate) {
this.headerCheckbox.indeterminate = true;
if (!this.headSelectorBaseTemplate.indeterminate) {
this.headSelectorBaseTemplate.indeterminate = true;
}
if (this.allRowsSelected) {
this.allRowsSelected = false;
Expand Down Expand Up @@ -4892,7 +4925,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
newSelectionAsSet.add(args.newSelection[i]);
}
this.selection.set(this.id, newSelectionAsSet);
this.checkHeaderCheckboxStatus(headerStatus);
this.calculateRowSelectionStatus(headerStatus);
}

/**
Expand Down Expand Up @@ -4925,7 +4958,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
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 { IgxSelectorsModule } from './igx-selection.module';
/**
* @hidden
*/
Expand Down Expand Up @@ -193,7 +194,8 @@ import { IgxRowDragModule } from './row-drag.directive';
IgxGridPipesModule,
IgxGridExcelStyleFilteringModule,
IgxRowDragModule,
IgxPaginatorModule
IgxPaginatorModule,
IgxSelectorsModule
],
providers: [
IgxGridSelectionService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
<ng-container *ngTemplateOutlet="this.grid.dragIndicatorIconTemplate ? this.grid.dragIndicatorIconTemplate : this.grid.dragIndicatorIconBase"></ng-container>
</div>
</ng-container>
<ng-container *ngIf="showRowCheckboxes">
<ng-container *ngIf="showRowSelectors">
<div class="igx-grid__cbx-selection">
<igx-checkbox [checked]="isSelected" [disabled]="deleted" (change)="onCheckboxClick($event)" disableRipple="true" [disableTransitions]="grid.disableTransitions" [aria-label]="rowCheckboxAriaLabel"></igx-checkbox>
<ng-template *ngTemplateOutlet="
this.grid.rowSelectorTemplate ? this.grid.rowSelectorTemplate : rowSelectorBaseTemplate;
context: {$implicit: {index: dataRowIndex, rowID: rowID, selected: isSelected}}">
</ng-template>
</div>
</ng-container>

Expand Down Expand Up @@ -100,3 +103,9 @@
</div>
</ng-template>
</ng-container>

<ng-template #rowSelectorBaseTemplate>
<igx-checkbox [checked]="isSelected" [disabled]="deleted" (change)="onRowSelect($event)" disableRipple="true"
[disableTransitions]="this.grid.disableTransitions" [aria-label]="rowCheckboxAriaLabel">
</igx-checkbox>
</ng-template>
22 changes: 15 additions & 7 deletions projects/igniteui-angular/src/lib/grids/grid/grid.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@
}" #headerDragContainer>
<div style="visibility: hidden;">
<ng-container
*ngTemplateOutlet="this.dragIndicatorIconTemplate ? this.dragIndicatorIconTemplate : this.dragIndicatorIconBase">
*ngTemplateOutlet="this.dragIndicatorIconTemplate ? this.dragIndicatorIconTemplate : dragIndicatorIconBase">
</ng-container>
</div>
</div>
</ng-container>
<ng-container *ngIf="showRowCheckboxes">
<div class="igx-grid__cbx-selection" #headerCheckboxContainer [ngClass]="{
<ng-container *ngIf="showRowSelectors">
<div class="igx-grid__cbx-selection" #headerSelectorContainer [ngClass]="{
'igx-grid__cbx-selection--push': filteringService.isFilterRowVisible
}">
<igx-checkbox [checked]="allRowsSelected" (change)="onHeaderCheckboxClick($event, filteredData)"
disableRipple="true" [aria-label]="headerCheckboxAriaLabel" #headerCheckbox></igx-checkbox>
<ng-template #headSelector
*ngTemplateOutlet="
this.headSelectorTemplate ? this.headSelectorTemplate : headSelectorBaseTemplate">
</ng-template>
</div>
</ng-container>
<ng-container *ngIf="pinnedColumns.length > 0">
Expand Down Expand Up @@ -116,7 +118,7 @@
[igxForItemSize]="hasColumnLayouts ? rowHeight * multiRowLayoutRowSize + 1 : renderedRowHeight"
#verticalScrollContainer (onChunkPreload)="dataLoading($event)">
<ng-template #record_template>
<igx-grid-row [gridID]="id" [index]="rowIndex" [rowData]="rowData" #row>
<igx-grid-row [rowSelected]="rowSelected" [gridID]="id" [index]="rowIndex" [rowData]="rowData" #row>
</igx-grid-row>
</ng-template>
<ng-template #group_template>
Expand Down Expand Up @@ -237,5 +239,11 @@
<igx-icon fontSet="material">drag_indicator</igx-icon>
</ng-template>


<ng-template #headSelectorBaseTemplate>
<igx-checkbox [checked]="allRowsSelected" (change)="onHeadSelectorClick($event, filteredData)"
disableRipple="true" [aria-label]="headerCheckboxAriaLabel"></igx-checkbox>
</ng-template>

<igx-grid-column-resizer *ngIf="colResizingService.showResizer"></igx-grid-column-resizer>
<div class="igx-grid__outlet" #igxFilteringOverlayOutlet igxOverlayOutlet></div>
<div class="igx-grid__outlet" #igxFilteringOverlayOutlet igxOverlayOutlet></div>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { IDisplayDensityOptions, DisplayDensityToken } from '../../core/displayD
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
import { IBaseChipEventArgs, IChipClickEventArgs, IChipKeyDownEventArgs } from '../../chips/chip.component';
import { IChipsAreaReorderEventArgs } from '../../chips/chips-area.component';
import { DataUtil } from '../../data-operations/data-util';
import { IgxSelectionAPIService } from '../../core/selection';
import { TransactionService, Transaction, State } from '../../services/transaction/transaction';
import { DOCUMENT } from '@angular/common';
Expand All @@ -31,6 +30,7 @@ import { IgxOverlayService } from '../../services/index';
import { IgxForOfSyncService } from '../../directives/for-of/for_of.sync.service';
import { IgxDragIndicatorIconDirective } from '../row-drag.directive';
import { IgxGridMRLNavigationService } from '../grid-mrl-navigation.service';
import { IgxRowSelectorDirective, IgxHeadSelectorDirective } from '../igx-selection.module';

let NEXT_ID = 0;

Expand Down Expand Up @@ -493,6 +493,12 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB
@ContentChild(IgxDragIndicatorIconDirective, { read: TemplateRef, static: true })
public dragIndicatorIconTemplate: TemplateRef<any> = null;

@ContentChild(IgxRowSelectorDirective, { read: TemplateRef, static: true })
public rowSelectorTemplate: TemplateRef<any>;

@ContentChild(IgxHeadSelectorDirective, { read: TemplateRef, static: true })
public headSelectorTemplate: TemplateRef<any>;

@ViewChildren(IgxGridGroupByRowComponent, { read: IgxGridGroupByRowComponent })
private _groupsRowList: QueryList<IgxGridGroupByRowComponent>;

Expand Down
20 changes: 20 additions & 0 deletions projects/igniteui-angular/src/lib/grids/igx-selection.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Directive, NgModule } from '@angular/core';

@Directive({
selector: '[igxRowSelector]'
})
export class IgxRowSelectorDirective {
}

@Directive({
selector: '[igxHeadSelector]'
})
export class IgxHeadSelectorDirective {
}

@NgModule({
declarations: [IgxRowSelectorDirective, IgxHeadSelectorDirective],
exports: [IgxRowSelectorDirective, IgxHeadSelectorDirective]
})
export class IgxSelectorsModule {
}
Loading

0 comments on commit 3c8c632

Please sign in to comment.