Skip to content

Commit 09c3d67

Browse files
author
Fernando Gonzalez Goncharov
committed
feat(dynamic-table): introduce dynamic-table module
Closes #6
1 parent 67931c9 commit 09c3d67

31 files changed

Lines changed: 3944 additions & 2682 deletions

package-lock.json

Lines changed: 2640 additions & 2640 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projects/ng-rocketparts/src/lib/components/dynamic-table/components/dynamic-table-cell/dynamic-table-cell.component.html

Whitespace-only changes.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import {
2+
ChangeDetectionStrategy,
3+
Component,
4+
ElementRef,
5+
HostBinding,
6+
Input,
7+
OnChanges,
8+
OnInit,
9+
SimpleChanges,
10+
ViewEncapsulation
11+
} from '@angular/core';
12+
import { get, uniq } from 'lodash';
13+
14+
import { AbstractDynamicCellComponent } from '../../helpers';
15+
import { DynamicTableDecoratorService } from '../../services/dynamic-table-decorator.service';
16+
17+
@Component({
18+
selector: '[ngrDynamicTableCell]', // tslint:disable-line:component-selector
19+
templateUrl: './dynamic-table-cell.component.html',
20+
changeDetection: ChangeDetectionStrategy.OnPush,
21+
encapsulation: ViewEncapsulation.None
22+
})
23+
export class DynamicTableCellComponent extends AbstractDynamicCellComponent
24+
implements OnInit, OnChanges {
25+
@Input()
26+
decorator: string;
27+
28+
@Input()
29+
decoratorOptions: any;
30+
31+
@Input()
32+
classPrefix = 'ngr-dynamic-table-cell';
33+
34+
@HostBinding('class')
35+
get classNames() {
36+
const externalClasses = this.el.nativeElement.className.split(' ');
37+
const decoratorClass = this.decorator
38+
? `${this.classPrefix}--${this.decorator}`
39+
: '';
40+
const styleHintClasses =
41+
this.decoratorOptions && this.decoratorOptions.styleHints
42+
? this.decoratorOptions.styleHints.map(
43+
styleHint => `${this.classPrefix}--${styleHint}`
44+
)
45+
: [];
46+
const cellStyleHints =
47+
this.decoratorOptions &&
48+
this.decoratorOptions.styleHintPath &&
49+
this.data
50+
? get<string[]>(this.data, this.decoratorOptions.styleHintPath)
51+
: [];
52+
const cellStyleHintClasses = cellStyleHints.map(
53+
styleHint => `${this.classPrefix}--${styleHint}`
54+
);
55+
return uniq(
56+
[
57+
...externalClasses,
58+
this.classPrefix,
59+
decoratorClass,
60+
...styleHintClasses
61+
].filter(Boolean)
62+
).join(' ');
63+
}
64+
65+
@HostBinding('innerHtml')
66+
content: string;
67+
68+
constructor(
69+
private decoratorService: DynamicTableDecoratorService,
70+
private el: ElementRef
71+
) {
72+
super();
73+
}
74+
75+
ngOnInit() {}
76+
77+
ngOnChanges(changes: SimpleChanges) {
78+
if (
79+
changes['decorator'] ||
80+
changes['decoratorOptions'] ||
81+
changes['data'] ||
82+
changes['path']
83+
) {
84+
this._updateComponent();
85+
}
86+
}
87+
88+
protected _updateComponent() {
89+
this.content = this.decoratorService.applyDecorator(
90+
this.decorator,
91+
this.data,
92+
this.path,
93+
this.decoratorOptions
94+
);
95+
}
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div #componentContainer></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import {
2+
AfterViewInit,
3+
ChangeDetectionStrategy,
4+
Component,
5+
ComponentFactoryResolver,
6+
ComponentRef,
7+
EventEmitter,
8+
HostBinding,
9+
Injector,
10+
Input,
11+
OnChanges,
12+
OnInit,
13+
Output,
14+
SimpleChange,
15+
SimpleChanges,
16+
ViewChild,
17+
ViewContainerRef,
18+
ViewEncapsulation
19+
} from '@angular/core';
20+
import { Subscription } from 'rxjs';
21+
import { uniq } from 'lodash';
22+
23+
import {
24+
AbstractDynamicCellComponent,
25+
ComponentRegistries,
26+
getInjectionTokenForComponentType
27+
} from '../../helpers';
28+
import { DynamicTableRowData } from '../../models/dynamic-table.model';
29+
30+
/**
31+
* Component that is used with the `component` decorator options to inject a custom component into the table cell
32+
*/
33+
@Component({
34+
selector: '[ngrDynamicTableComponentCell]', // tslint:disable-line:component-selector
35+
templateUrl: './dynamic-table-component-cell.component.html',
36+
changeDetection: ChangeDetectionStrategy.OnPush,
37+
encapsulation: ViewEncapsulation.None
38+
})
39+
export class DynamicTableComponentCellComponent
40+
extends AbstractDynamicCellComponent
41+
implements OnInit, OnChanges, AfterViewInit {
42+
@Input()
43+
component: string;
44+
45+
@Input()
46+
componentOptions: any;
47+
48+
@Input()
49+
decoratorOptions: any;
50+
51+
@Input()
52+
classPrefix = 'ngr-dynamic-table-cell';
53+
54+
@Output()
55+
event: EventEmitter<any> = new EventEmitter();
56+
57+
@ViewChild('componentContainer', { read: ViewContainerRef })
58+
componentContainer: ViewContainerRef;
59+
60+
private isViewInitialized = false;
61+
62+
private componentRef: ComponentRef<DynamicTableComponentCell>;
63+
64+
private componentEventSubscription: Subscription;
65+
66+
constructor(
67+
private injector: Injector,
68+
private componentFactoryResolver: ComponentFactoryResolver
69+
) {
70+
super();
71+
}
72+
73+
@HostBinding('class')
74+
get classNames() {
75+
const styleHintClasses =
76+
this.decoratorOptions && this.decoratorOptions.styleHints
77+
? this.decoratorOptions.styleHints.map(
78+
styleHint => `${this.classPrefix}--${styleHint}`
79+
)
80+
: [];
81+
return uniq(
82+
[
83+
'dynamic-table-cell',
84+
'dynamic-table-cell--component',
85+
...styleHintClasses
86+
].filter(Boolean)
87+
).join(' ');
88+
}
89+
90+
ngOnInit() {}
91+
92+
ngAfterViewInit() {
93+
this.isViewInitialized = true;
94+
this._updateComponent({});
95+
}
96+
97+
ngOnChanges(changes: SimpleChanges) {
98+
if (changes['component']) {
99+
this._updateComponent(changes, true);
100+
} else {
101+
this._updateComponent(changes);
102+
}
103+
}
104+
105+
/**
106+
* Update the injected component
107+
* @param changes
108+
* @param recreate
109+
*/
110+
protected _updateComponent(changes: SimpleChanges, recreate = false) {
111+
let compChanges = {};
112+
if (!this.componentRef || recreate) {
113+
if (this.componentRef && recreate) {
114+
this.componentRef.destroy();
115+
}
116+
const injectionToken = getInjectionTokenForComponentType<
117+
DynamicTableComponentCell
118+
>(ComponentRegistries.TABLE_CELL, this.component);
119+
if (injectionToken) {
120+
const type = this.injector.get(injectionToken);
121+
const factory = this.componentFactoryResolver.resolveComponentFactory(
122+
type
123+
);
124+
this.componentRef = this.componentContainer.createComponent(
125+
factory
126+
);
127+
compChanges = {
128+
data: new SimpleChange(null, this.data, true),
129+
path: new SimpleChange(null, this.path, true),
130+
options: new SimpleChange(null, this.componentOptions, true)
131+
};
132+
}
133+
} else {
134+
if (changes['data']) {
135+
compChanges['data'] = changes['data'];
136+
}
137+
if (changes['path']) {
138+
compChanges['path'] = changes['path'];
139+
}
140+
if (changes['componentOptions']) {
141+
compChanges['options'] = changes['componentOptions'];
142+
}
143+
}
144+
145+
if (this.componentRef && this.componentRef.instance) {
146+
this.componentRef.instance.data = this.data;
147+
this.componentRef.instance.path = this.path;
148+
this.componentRef.instance.options = this.componentOptions;
149+
150+
if (this.componentEventSubscription) {
151+
this.componentEventSubscription.unsubscribe();
152+
}
153+
if (this.componentRef.instance.event) {
154+
this.componentEventSubscription = this.componentRef.instance.event.subscribe(
155+
this.event
156+
);
157+
}
158+
159+
if (this.componentRef.instance.ngOnChanges) {
160+
this.componentRef.instance.ngOnChanges(compChanges);
161+
}
162+
}
163+
}
164+
}
165+
166+
export interface DynamicTableComponentCell extends OnChanges {
167+
data: DynamicTableRowData;
168+
169+
options: any;
170+
171+
path: string;
172+
173+
event?: EventEmitter<any>;
174+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<a [href]="link">
2+
{{ label }}<i *ngIf="options.icon" class="external-link-icon far fa-{{options.icon}}"></i>
3+
</a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Component, Input, ViewEncapsulation } from '@angular/core';
2+
import { get } from 'lodash';
3+
4+
import { DynamicTableRowData } from '../../models/dynamic-table.model';
5+
import { DynamicTableComponentCell } from '../dynamic-table-component-cell/dynamic-table-component-cell.component';
6+
import { AbstractDynamicCellComponent } from '../../helpers';
7+
8+
@Component({
9+
selector: 'ngr-dynamic-table-link-cell',
10+
templateUrl: './dynamic-table-link-cell.component.html',
11+
encapsulation: ViewEncapsulation.None
12+
})
13+
export class DynamicTableLinkCellComponent extends AbstractDynamicCellComponent
14+
implements DynamicTableComponentCell {
15+
@Input()
16+
data: DynamicTableRowData;
17+
@Input()
18+
options: any;
19+
@Input()
20+
path: string;
21+
22+
label = '';
23+
link = '';
24+
25+
constructor() {
26+
super();
27+
}
28+
29+
protected _updateComponent() {
30+
this.label = get(this.data, this.path) || this.options.label;
31+
this.link = get(this.data, this.options.linkPath as string);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<ng-container *ngFor="let column of config.columns">
2+
<td *ngIf="column.decorator === 'component'; else regularCell" ngrDynamicTableComponentCell [component]="column.decoratorOptions?.component"
3+
[decoratorOptions]="column.decoratorOptions" [componentOptions]="column.decoratorOptions?.componentOptions"
4+
[data]="data" [path]="column.path" (event)="onComponentEvent($event)"></td>
5+
<ng-template #regularCell>
6+
<td ngrDynamicTableCell [decorator]="column.decorator" [decoratorOptions]="column.decoratorOptions" [data]="data"
7+
[path]="column.path"></td>
8+
</ng-template>
9+
</ng-container>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Component,
3+
EventEmitter,
4+
Input,
5+
OnInit,
6+
Output,
7+
ViewEncapsulation
8+
} from '@angular/core';
9+
10+
import {
11+
DynamicTableConfig,
12+
DynamicTableRowData
13+
} from '../../models/dynamic-table.model';
14+
15+
@Component({
16+
selector: '[ngrDynamicTableRow]', // tslint:disable-line:component-selector
17+
templateUrl: './dynamic-table-row.component.html',
18+
encapsulation: ViewEncapsulation.None
19+
})
20+
export class DynamicTableRowComponent implements OnInit {
21+
@Input()
22+
config: DynamicTableConfig;
23+
24+
@Input()
25+
data: DynamicTableRowData;
26+
27+
@Input()
28+
selected: boolean;
29+
30+
@Output()
31+
toggleSelection: EventEmitter<boolean> = new EventEmitter<boolean>();
32+
33+
@Output()
34+
componentEvent: EventEmitter<any> = new EventEmitter();
35+
36+
constructor() {}
37+
38+
ngOnInit() {}
39+
40+
onComponentEvent(event: any) {
41+
this.componentEvent.next(event);
42+
}
43+
}

0 commit comments

Comments
 (0)