Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit 829e89d

Browse files
dlabrecqdgutride
authored andcommitted
feat(table): added datatable implementation
1 parent e648a0a commit 829e89d

22 files changed

+1408
-6
lines changed

config/webpack.demo.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,12 @@ module.exports = {
194194
*
195195
* See: https://www.npmjs.com/package/@ngtools/webpack
196196
*/
197+
/*
197198
new AotPlugin({
198199
entryModule: helpers.root('src/demo/app.module.ts#AppModule'),
199200
tsConfigPath: helpers.root('tsconfig-aot.json')
200201
}),
201-
202+
*/
202203
/**
203204
* Plugin: copy-webpack-plugin
204205
* Description: Copies individual files or entire directories to the build directory

index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ export { SortEvent } from './src/app/sort/sort-event';
101101
export { SortField } from './src/app/sort/sort-field';
102102
export { SortModule } from './src/app/sort/sort.module';
103103

104+
// Table
105+
export { DataTableConfig } from './src/app/table/datatable/datatable-config';
106+
export { DataTableComponent } from './src/app/table/datatable/datatable.component';
107+
export { DataTableDragulaDirective } from './src/app/table/datatable/datatable-dragula.directive';
108+
import { TableBase } from './src/app/table/table-base';
109+
import { TableBaseConfig } from './src/app/table/table-base-config';
110+
import { TableEvent } from './src/app/table/table-event';
111+
104112
// Toolbar
105113
export { ToolbarConfig } from './src/app/toolbar/toolbar-config';
106114
export { ToolbarComponent } from './src/app/toolbar/toolbar.component';

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@
7171
"patternfly": "^3.28.0"
7272
},
7373
"optionalDependencies": {
74+
"@swimlane/ngx-datatable": "^11.1.5",
7475
"angular-tree-component": "^6.0.0",
75-
"c3": "^0.4.15"
76+
"c3": "^0.4.15",
77+
"c3": "^0.4.15",
78+
"ng2-dragula": "^1.5.0"
7679
},
7780
"devDependencies": {
7881
"@angular/animations": "^4.0.1",

patternfly-ng.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { PipeModule } from './src/app/pipe/pipe.module';
1515
import { RemainingCharsCountModule } from './src/app/remaining-chars-count/remaining-chars-count.module';
1616
import { SampleModule } from './src/app/sample/sample.module';
1717
import { SortModule } from './src/app/sort/sort.module';
18+
import { TableModule } from './src/app/table/table.module';
1819
import { ToolbarModule } from './src/app/toolbar/toolbar.module';
1920
import { WizardModule } from './src/app/wizard/wizard.module';
2021

@@ -37,6 +38,7 @@ import { WizardModule } from './src/app/wizard/wizard.module';
3738
PipeModule,
3839
SampleModule,
3940
SortModule,
41+
TableModule,
4042
ToolbarModule,
4143
WizardModule
4244
]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TableBaseConfig } from '../table-base-config';
2+
3+
/**
4+
* An config containing properties for data table
5+
*/
6+
export class DataTableConfig extends TableBaseConfig {
7+
/**
8+
* Enable drag and drop. Default is false
9+
*/
10+
dragEnabled?: boolean;
11+
12+
/**
13+
* Show checkbox for selecting rows. Default is true
14+
*/
15+
showCheckbox?: boolean;
16+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import {
2+
AfterViewInit,
3+
Directive,
4+
ElementRef,
5+
EventEmitter,
6+
Input,
7+
OnChanges,
8+
OnDestroy,
9+
OnInit,
10+
Output,
11+
SimpleChange
12+
} from '@angular/core';
13+
import { dragula, DragulaService } from 'ng2-dragula';
14+
15+
@Directive({
16+
selector: 'ngx-datatable[dragulaName]'
17+
})
18+
export class DataTableDragulaDirective implements AfterViewInit, OnChanges, OnDestroy, OnInit {
19+
@Input() public dragulaName: string;
20+
@Input() public dragulaModel: any;
21+
@Input() public dragulaClassSelector: string = 'null';
22+
@Output() public dragulaDrop: EventEmitter<any> = new EventEmitter<any>();
23+
@Output() public dragulaDrag: EventEmitter<any> = new EventEmitter<any>();
24+
25+
subscriptionDrag: any = null;
26+
subscriptionDrop: any = null;
27+
28+
protected container: any;
29+
private drake: any;
30+
private el: ElementRef;
31+
private dragulaService: DragulaService;
32+
33+
public constructor(el: ElementRef, dragulaService: DragulaService) {
34+
this.el = el;
35+
this.dragulaService = dragulaService;
36+
}
37+
38+
ngOnInit() {
39+
}
40+
41+
ngAfterViewInit() {
42+
if (this.el) {
43+
let container = this.el;
44+
45+
// Check for the row's parent node: datatable-scroller
46+
// This is what you want to bind Dragula to, in order to drag sort
47+
if (container.nativeElement.querySelector('datatable-scroller')) {
48+
let rowParent = container.nativeElement.querySelector('datatable-scroller');
49+
50+
// Check if this Dragula already exists
51+
if (!this.dragulaService.find(this.dragulaName)) {
52+
53+
// Must assign the new rowParent as the container you want to pass to Dragula
54+
this.container = rowParent;
55+
this.initializeDragula();
56+
}
57+
}
58+
}
59+
}
60+
61+
ngOnChanges(changes: { dragulaModel?: SimpleChange }): void {
62+
63+
// Must update model on any changes
64+
// Otherwise it will fall out of sync with the 'dragulaModel'
65+
if (changes && changes.dragulaModel) {
66+
if (this.drake) {
67+
if (this.drake.models) {
68+
let modelIndex = this.drake.models.indexOf(changes.dragulaModel.previousValue);
69+
this.drake.models.splice(modelIndex, 1, changes.dragulaModel.currentValue);
70+
} else {
71+
this.drake.models = [changes.dragulaModel.currentValue];
72+
}
73+
}
74+
}
75+
}
76+
77+
ngOnDestroy() {
78+
79+
// Clear this Dragula always
80+
// comment out if you want to keep it
81+
if (this.dragulaService.find(this.dragulaName)) {
82+
this.dragulaService.destroy(this.dragulaName);
83+
}
84+
85+
// Clear DRAG and DROP subscription to prevent duplicates
86+
if (this.subscriptionDrag) {
87+
this.subscriptionDrag.unsubscribe();
88+
this.subscriptionDrag = null;
89+
}
90+
if (this.subscriptionDrop) {
91+
this.subscriptionDrop.unsubscribe();
92+
this.subscriptionDrop = null;
93+
}
94+
}
95+
96+
protected initializeDragula() {
97+
// console.log('initialized');
98+
// Create new Dragula container
99+
let bag = this.dragulaService.find(this.dragulaName);
100+
if (bag) {
101+
this.drake = bag.drake;
102+
this.checkModel();
103+
this.drake.containers.push(this.container);
104+
} else {
105+
106+
// Check if dragulaClassSelector was specified
107+
// *true:
108+
// - the dragulaClassSelector string will be used to match the class of the element clicked
109+
// - the element with the matching class name will be used to drag the row
110+
// *false:
111+
// - no class selector will be used
112+
// - the whole row will default back to being draggable
113+
if (this.dragulaClassSelector !== 'null') {
114+
let classSelector = this.dragulaClassSelector;
115+
let options = {
116+
moves: function(el: any, container: any, handle: any) {
117+
return handle.className === classSelector;
118+
}
119+
};
120+
this.drake = dragula([this.container], options);
121+
} else {
122+
this.drake = dragula([this.container]);
123+
}
124+
this.checkModel();
125+
this.dragulaService.add(this.dragulaName, this.drake);
126+
}
127+
128+
// Set DRAG and DROP subscriptions and callbacks
129+
this.subscriptionDrag = this.dragulaService.drag.subscribe((value: any) => {
130+
this.drag(value.slice(1));
131+
});
132+
this.subscriptionDrop = this.dragulaService.drop.subscribe((value: any) => {
133+
const [bagName, el, target, source] = value;
134+
135+
this.onDropModel(value.slice(1));
136+
});
137+
}
138+
139+
private checkModel() {
140+
if (this.dragulaModel) {
141+
if (this.drake.models) {
142+
this.drake.models.push(this.dragulaModel);
143+
} else {
144+
this.drake.models = [this.dragulaModel];
145+
}
146+
}
147+
}
148+
149+
private drag(args: any) {
150+
let [e, el] = args;
151+
// Todo: not implemented
152+
}
153+
154+
private onDropModel(args: any) {
155+
let [el, target, source] = args;
156+
157+
// Added emitter on any DROP action
158+
// console.log('EMITTER', args);
159+
this.dragulaDrop.emit(this.dragulaModel);
160+
}
161+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<div class="pfng-datatable">
2+
<pfng-toolbar
3+
[config]="config.toolbarConfig"
4+
[actionTemplate]="actionTemplate"
5+
(onActionSelect)="handleAction($event)"
6+
(onFilterChange)="handleFilterChange($event)"
7+
(onFilterFieldSelect)="handleFilterFieldSelect($event)"
8+
(onFilterTypeAhead)="handleFilterTypeAhead($event)"
9+
(onSortChange)="handleSortChange($event)"
10+
(onViewSelect)="handleViewSelect($event)"
11+
*ngIf="config.toolbarConfig">
12+
</pfng-toolbar>
13+
<ngx-datatable #datatable
14+
class="bootstrap"
15+
[rows]="rows"
16+
[columns]="cols"
17+
[columnMode]="'force'"
18+
[dragulaClassSelector]="'pfng-datatable-dnd-header'"
19+
[dragulaModel]="rowsModel"
20+
[dragulaName]="dragulaName"
21+
[headerHeight]="50"
22+
[selected]="selectedRows"
23+
[rowHeight]="'auto'"
24+
[reorderable]="true"
25+
(dragulaDrop)="handleDrop($event)"
26+
(dragulaDrag)="handleDrag($event)"
27+
*ngIf="showTable">
28+
<ng-template #headerTmpl></ng-template>
29+
<ng-template #dndTmpl>
30+
<div class="pfng-datatable-dnd-container">
31+
<div class="pfng-datatable-dnd-header"></div>
32+
</div>
33+
</ng-template>
34+
<ng-template #selectTmpl let-row="row">
35+
<div class="pfng-datatable-select">
36+
<input type="checkbox" value="row.selected"
37+
[(ngModel)]="row.selected"
38+
(ngModelChange)="selectionChange(row)">
39+
</div>
40+
</ng-template>
41+
</ngx-datatable>
42+
<pfng-pagination
43+
[config]="config.paginationConfig"
44+
(onPageNumberChange)="handlePageNumber($event)"
45+
(onPageSizeChange)="handlePageSize($event)"
46+
*ngIf="config.paginationConfig"></pfng-pagination>
47+
</div>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@import (reference) '../../../assets/stylesheets/patternfly-ng';
2+
3+
.pfng-datatable {
4+
.row.toolbar-pf {
5+
margin-left: 0;
6+
margin-right: 0;
7+
}
8+
.table-view-pf-select-results {
9+
padding-bottom: 10px;
10+
}
11+
}
12+
13+
.pfng-datatable-dnd-container {
14+
align-self: stretch;
15+
display: flex;
16+
}
17+
18+
.pfng-datatable-dnd-header {
19+
margin-right: 10px;
20+
&:before {
21+
background-image: linear-gradient(to bottom, @color-pf-blue-400 60%, @color-pf-white 0%);
22+
background-position: left;
23+
background-repeat: repeat-y;
24+
background-size: 2px 5px;
25+
border: 4px solid @color-pf-blue-400;
26+
border-color: @color-pf-blue-500;
27+
content: '';
28+
height: 100%;
29+
left: -4px;
30+
position: absolute;
31+
top: 0;
32+
width: 10px;
33+
}
34+
}
35+
36+
.pfng-datatable-select {
37+
margin-left: 5px;
38+
}

0 commit comments

Comments
 (0)