-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ngrid-bootstrap): selection column
- Loading branch information
1 parent
0494678
commit ab09209
Showing
9 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Selection implementation using bootstrap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", | ||
"dest": "../../../dist/@pebula/ngrid-bootstrap/selection-column", | ||
"deleteDestPath": false, | ||
"lib": { | ||
"entryFile": "src/index.ts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"name": "@pebula/ngrid-bootstrap/selection-column" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { PblNgridBsSelectionModule } from './lib/bs-selection.module'; |
108 changes: 108 additions & 0 deletions
108
libs/ngrid-bootstrap/selection-column/src/lib/bs-selection-plugin.directive.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Directive, Injector, Input, OnDestroy, ComponentFactoryResolver, ComponentRef } from '@angular/core'; | ||
|
||
import { PblNgridComponent, PblNgridPluginController } from '@pebula/ngrid'; | ||
|
||
import { PblNgridBsSelectionComponent } from './bs-selection.component'; | ||
|
||
declare module '@pebula/ngrid/lib/ext/types' { | ||
interface PblNgridPluginExtension { | ||
bsSelectionColumn?: PblNgridBsSelectionPlugin; | ||
} | ||
} | ||
|
||
export const PLUGIN_KEY: 'bsSelectionColumn' = 'bsSelectionColumn'; | ||
|
||
@Directive({ selector: 'pbl-ngrid[bsSelectionColumn]' }) | ||
export class PblNgridBsSelectionPlugin implements OnDestroy { | ||
|
||
@Input() get isCheckboxDisabled() { return this._isCheckboxDisabled; } | ||
set isCheckboxDisabled(value: (row: any) => boolean ) { | ||
if (value !== this._isCheckboxDisabled) { | ||
this._isCheckboxDisabled = value; | ||
if (this.cmpRef && value) { | ||
this.cmpRef.instance.isCheckboxDisabled = value; | ||
this.cmpRef.changeDetectorRef.detectChanges(); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Add's a selection column using material's `mat-checkbox` in the column specified. | ||
*/ | ||
@Input() get bsSelectionColumn(): string { return this._name; } | ||
set bsSelectionColumn(value: string ) { | ||
if (value !== this._name) { | ||
this._name = value; | ||
if (!value) { | ||
if (this.cmpRef) { | ||
this.cmpRef.destroy(); | ||
this.cmpRef = undefined; | ||
} | ||
} else { | ||
if (!this.cmpRef) { | ||
this.cmpRef = this.cfr.resolveComponentFactory(PblNgridBsSelectionComponent).create(this.injector); | ||
this.cmpRef.instance.table = this.table; | ||
if (this._bulkSelectMode) { | ||
this.cmpRef.instance.bulkSelectMode = this._bulkSelectMode; | ||
} | ||
this.cmpRef.instance.selectionClass = this._selectionClass; | ||
} | ||
if (this.isCheckboxDisabled) { | ||
this.cmpRef.instance.isCheckboxDisabled = this.isCheckboxDisabled; | ||
} | ||
this.cmpRef.instance.name = value; | ||
this.cmpRef.changeDetectorRef.detectChanges(); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Defines the behavior when clicking on the bulk select checkbox (header). | ||
* There are 2 options: | ||
* | ||
* - all: Will select all items in the current collection | ||
* - view: Will select only the rendered items in the view | ||
* | ||
* The default value is `all` | ||
*/ | ||
@Input() get bulkSelectMode(): 'all' | 'view' | 'none' { return this._bulkSelectMode; } | ||
set bulkSelectMode(value: 'all' | 'view' | 'none') { | ||
if (value !== this._bulkSelectMode) { | ||
this._bulkSelectMode = value; | ||
if (this.cmpRef) { | ||
this.cmpRef.instance.bulkSelectMode = value; | ||
} | ||
} | ||
} | ||
|
||
@Input() get bsSelectionClass(): string { return this._selectionClass; } | ||
set matCheckboxSelectionColor(value: string) { | ||
if (value !== this._selectionClass) { | ||
this._selectionClass = value; | ||
if (this.cmpRef) { | ||
this.cmpRef.instance.selectionClass = value; | ||
} | ||
} | ||
} | ||
|
||
private _name: string; | ||
private _bulkSelectMode: 'all' | 'view' | 'none'; | ||
private _selectionClass: string = ''; | ||
private cmpRef: ComponentRef<PblNgridBsSelectionComponent>; | ||
private _removePlugin: (table: PblNgridComponent<any>) => void; | ||
private _isCheckboxDisabled: (row: any) => boolean; | ||
|
||
constructor(private table: PblNgridComponent<any>, | ||
private cfr: ComponentFactoryResolver, | ||
private injector: Injector, | ||
pluginCtrl: PblNgridPluginController) { | ||
this._removePlugin = pluginCtrl.setPlugin(PLUGIN_KEY, this); | ||
} | ||
|
||
ngOnDestroy() { | ||
if (this.cmpRef) { | ||
this.cmpRef.destroy(); | ||
} | ||
this._removePlugin(this.table); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
libs/ngrid-bootstrap/selection-column/src/lib/bs-selection.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<ng-container *pblNgridHeaderCellDef="name; col as col;"> | ||
<label *ngIf="bulkSelectMode !== 'none'" | ||
[class]="selectionClass"> | ||
<input type="checkbox" | ||
[checked]="allSelected" | ||
(input)="masterToggle()"> | ||
</label> | ||
</ng-container> | ||
|
||
<label *pblNgridCellDef="name; row as row;"> | ||
<input type="checkbox" | ||
[class]="selectionClass" | ||
[checked]="selection.isSelected(row)" | ||
[disabled]="isCheckboxDisabled(row)" | ||
(input)="rowItemChange(row)"> | ||
</label> | ||
|
||
<span *pblNgridFooterCellDef="name; col as col;">{{ length ? length : '' }}</span> |
Empty file.
168 changes: 168 additions & 0 deletions
168
libs/ngrid-bootstrap/selection-column/src/lib/bs-selection.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { Component, Input, ViewChild, ViewEncapsulation, AfterViewInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; | ||
import { SelectionModel } from '@angular/cdk/collections'; | ||
|
||
import { unrx } from '@pebula/ngrid/core'; | ||
import { | ||
PblNgridComponent, | ||
PblNgridHeaderCellDefDirective, | ||
PblNgridCellDefDirective, | ||
PblNgridFooterCellDefDirective, | ||
PblNgridPluginController, | ||
} from '@pebula/ngrid'; | ||
|
||
const ALWAYS_FALSE_FN = () => false; | ||
|
||
@Component({ | ||
selector: 'pbl-ngrid-bs-checkbox', | ||
templateUrl: './bs-selection.component.html', | ||
styleUrls: ['./bs-selection.component.scss'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
encapsulation: ViewEncapsulation.None, | ||
}) | ||
export class PblNgridBsSelectionComponent implements AfterViewInit, OnDestroy { | ||
/** | ||
* Unique name for the checkbox column. | ||
* When not set, the name 'checkbox' is used. | ||
* | ||
**/ | ||
@Input() name: string; | ||
|
||
/** | ||
* Defines the behavior when clicking on the bulk select checkbox (header). | ||
* There are 2 options: | ||
* | ||
* - all: Will select all items in the current collection | ||
* - view: Will select only the rendered items in the view | ||
* | ||
* The default value is `all` | ||
*/ | ||
@Input() get bulkSelectMode(): 'all' | 'view' | 'none' { return this._bulkSelectMode; } | ||
set bulkSelectMode(value: 'all' | 'view' | 'none') { | ||
if (value !== this._bulkSelectMode) { | ||
this._bulkSelectMode = value; | ||
this.setupSelection(); | ||
} | ||
} | ||
/** | ||
* A Custom selection model, optional. | ||
* If not set, the selection model from the DataSource is used. | ||
*/ | ||
@Input() get selection(): SelectionModel<any> { | ||
return this._selection; | ||
} | ||
set selection(value: SelectionModel<any>) { | ||
if (value !== this._selection) { | ||
this._selection = value; | ||
this.setupSelection(); | ||
} | ||
} | ||
|
||
@Input() get isCheckboxDisabled() { return this._isCheckboxDisabled; } | ||
set isCheckboxDisabled(value: (row: any) => boolean) { | ||
if (value !== this._isCheckboxDisabled) { | ||
this._isCheckboxDisabled = value; | ||
if (!this._isCheckboxDisabled || typeof this._isCheckboxDisabled !== 'function') { | ||
this._isCheckboxDisabled = ALWAYS_FALSE_FN; | ||
} | ||
} | ||
} | ||
|
||
@Input() get selectionClass(): string { return this._selectionClass; } | ||
set selectionClass(value: string) { | ||
if (value !== this._selectionClass) { | ||
this._selectionClass = value; | ||
if (this.table.isInit) { | ||
this.markAndDetect(); | ||
} | ||
} | ||
} | ||
|
||
@ViewChild(PblNgridHeaderCellDefDirective, { static: true }) headerDef: PblNgridHeaderCellDefDirective<any>; | ||
@ViewChild(PblNgridCellDefDirective, { static: true }) cellDef: PblNgridCellDefDirective<any>; | ||
@ViewChild(PblNgridFooterCellDefDirective, { static: true }) footerDef: PblNgridFooterCellDefDirective<any>; | ||
|
||
allSelected = false; | ||
length: number; | ||
|
||
private _selection: SelectionModel<any>; | ||
private _bulkSelectMode: 'all' | 'view' | 'none'; | ||
private _isCheckboxDisabled: (row: any) => boolean = ALWAYS_FALSE_FN; | ||
private _selectionClass: string; | ||
|
||
constructor(public table: PblNgridComponent<any>, private cdr: ChangeDetectorRef) { | ||
const pluginCtrl = PblNgridPluginController.find(table); | ||
pluginCtrl.events | ||
.pipe(unrx(this)) | ||
.subscribe( e => { | ||
if (e.kind === 'onDataSource') { | ||
this.selection = e.curr.selection; | ||
} | ||
}); | ||
|
||
} | ||
|
||
ngAfterViewInit(): void { | ||
if (!this.selection && this.table.ds) { | ||
this.selection = this.table.ds.selection; | ||
} | ||
|
||
const registry = this.table.registry; | ||
registry.addMulti('headerCell', this.headerDef); | ||
registry.addMulti('tableCell', this.cellDef); | ||
registry.addMulti('footerCell', this.footerDef); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
unrx.kill(this); | ||
} | ||
|
||
masterToggle(): void { | ||
if (this.allSelected) { | ||
this.selection.clear(); | ||
} else { | ||
const selected = this.getCollection().filter(data => !this._isCheckboxDisabled(data)); | ||
this.selection.select(...selected); | ||
} | ||
} | ||
|
||
rowItemChange(row: any): void { | ||
this.selection.toggle(row); | ||
this.markAndDetect(); | ||
} | ||
|
||
onInput(a,b){ | ||
console.log(a,b) | ||
} | ||
private getCollection() { | ||
const { ds } = this.table; | ||
return this.bulkSelectMode === 'view' ? ds.renderedData : ds.source; | ||
} | ||
|
||
private setupSelection(): void { | ||
unrx.kill(this, this.table); | ||
if (this._selection) { | ||
this.length = this.selection.selected.length; | ||
this.selection.changed | ||
.pipe(unrx(this, this.table)) | ||
.subscribe(() => this.handleSelectionChanged()); | ||
const changeSource = this.bulkSelectMode === 'view' ? this.table.ds.onRenderedDataChanged : this.table.ds.onSourceChanged; | ||
changeSource | ||
.pipe(unrx(this, this.table)) | ||
.subscribe(() => this.handleSelectionChanged()); | ||
} else { | ||
this.length = 0; | ||
} | ||
} | ||
|
||
private handleSelectionChanged() { | ||
const { length } = this.getCollection().filter(data => !this._isCheckboxDisabled(data)); | ||
this.allSelected = !this.selection.isEmpty() && this.selection.selected.length === length; | ||
this.length = this.selection.selected.length; | ||
this.markAndDetect(); | ||
} | ||
|
||
private markAndDetect() { | ||
this.cdr.markForCheck(); | ||
this.cdr.detectChanges(); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
libs/ngrid-bootstrap/selection-column/src/lib/bs-selection.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { CommonModule } from '@angular/common'; | ||
import { MatCheckboxModule } from '@angular/material/checkbox'; | ||
|
||
import { PblNgridModule, ngridPlugin } from '@pebula/ngrid'; | ||
import { PblNgridBsSelectionPlugin, PLUGIN_KEY } from './bs-selection-plugin.directive'; | ||
import { PblNgridBsSelectionComponent } from './bs-selection.component'; | ||
|
||
@NgModule({ | ||
imports: [ CommonModule, MatCheckboxModule, PblNgridModule ], | ||
declarations: [ PblNgridBsSelectionPlugin, PblNgridBsSelectionComponent ], | ||
exports: [ PblNgridBsSelectionPlugin, PblNgridBsSelectionComponent ], | ||
// TODO(REFACTOR_REF 2): remove when ViewEngine is no longer supported by angular (V12 ???) | ||
entryComponents: [ PblNgridBsSelectionComponent ] | ||
}) | ||
export class PblNgridBsSelectionModule { | ||
static readonly NGRID_PLUGIN = ngridPlugin({ id: PLUGIN_KEY }, PblNgridBsSelectionPlugin); | ||
} |