Skip to content

Commit 1675bd7

Browse files
committed
refactor(table): signal inputs, host bindings, cleanup, tests
1 parent 994ecc3 commit 1675bd7

File tree

2 files changed

+152
-50
lines changed

2 files changed

+152
-50
lines changed
Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,113 @@
1-
import { TestBed } from '@angular/core/testing';
2-
import { ElementRef, Renderer2 } from '@angular/core';
1+
import { Component, DebugElement, ElementRef, Renderer2 } from '@angular/core';
2+
import { ComponentFixture, TestBed } from '@angular/core/testing';
3+
import { By } from '@angular/platform-browser';
34

45
import { TableDirective } from './table.directive';
6+
import { Colors } from '../coreui.types';
7+
import { TableActiveDirective } from './table-active.directive';
8+
9+
@Component({
10+
template: `
11+
<table
12+
cTable
13+
[align]="align"
14+
[borderColor]="borderColor"
15+
[bordered]="bordered"
16+
[borderless]="borderless"
17+
[caption]="caption"
18+
[color]="color"
19+
[hover]="hover"
20+
[small]="small"
21+
[striped]="striped"
22+
[stripedColumns]="stripedColumns"
23+
[responsive]="true"
24+
></table>
25+
`,
26+
imports: [TableDirective]
27+
})
28+
class TestComponent {
29+
align: 'bottom' | 'middle' | 'top' = 'middle';
30+
borderColor: Colors = 'primary';
31+
bordered: boolean = true;
32+
borderless: boolean = false;
33+
caption = 'top' as const;
34+
color: Colors = 'secondary';
35+
hover: boolean = true;
36+
small: boolean = true;
37+
striped: boolean = true;
38+
stripedColumns: boolean = true;
39+
}
540

641
class MockElementRef extends ElementRef {}
742

843
describe('TableDirective', () => {
44+
let component: TestComponent;
45+
let fixture: ComponentFixture<TestComponent>;
46+
let debugElement: DebugElement;
47+
let directive: TableDirective;
48+
949
beforeEach(() => {
1050
TestBed.configureTestingModule({
51+
imports: [TestComponent],
1152
providers: [Renderer2, { provide: ElementRef, useClass: MockElementRef }]
1253
});
54+
fixture = TestBed.createComponent(TestComponent);
55+
debugElement = fixture.debugElement.query(By.directive(TableDirective));
56+
directive = debugElement.injector.get(TableDirective);
57+
component = fixture.componentInstance;
58+
fixture.detectChanges();
1359
});
1460

1561
it('should create an instance', () => {
62+
expect(directive).toBeTruthy();
1663
TestBed.runInInjectionContext(() => {
17-
const directive = new TableDirective();
64+
const directive = new TableActiveDirective();
1865
expect(directive).toBeTruthy();
1966
});
2067
});
68+
69+
it('should apply align input', () => {
70+
expect(directive.align()).toBe('middle');
71+
});
72+
73+
it('should apply borderColor input', () => {
74+
expect(directive.borderColor()).toBe('primary');
75+
});
76+
77+
it('should apply bordered input', () => {
78+
expect(directive.bordered()).toBe(true);
79+
});
80+
81+
it('should apply borderless input', () => {
82+
expect(directive.borderless()).toBe(false);
83+
});
84+
85+
it('should apply caption input', () => {
86+
expect(directive.caption()).toBe('top');
87+
});
88+
89+
it('should apply color input', () => {
90+
expect(directive.color()).toBe('secondary');
91+
});
92+
93+
it('should have responsive wrapper', () => {
94+
const parentElement = debugElement.nativeElement.parentElement;
95+
const classes = parentElement.classList;
96+
expect(classes).toContain('table-responsive');
97+
});
98+
99+
it('should apply correct host classes', () => {
100+
const classes = debugElement.nativeElement.classList;
101+
102+
expect(classes).toContain('table');
103+
expect(classes).toContain('align-middle');
104+
expect(classes).toContain('caption-top');
105+
expect(classes).toContain('border-primary');
106+
expect(classes).toContain('table-bordered');
107+
expect(classes).toContain('table-secondary');
108+
expect(classes).toContain('table-hover');
109+
expect(classes).toContain('table-sm');
110+
expect(classes).toContain('table-striped');
111+
expect(classes).toContain('table-striped-columns');
112+
});
21113
});
Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,125 @@
1-
import { booleanAttribute, Directive, ElementRef, HostBinding, inject, Input, OnInit, Renderer2 } from '@angular/core';
1+
import { booleanAttribute, computed, Directive, effect, ElementRef, inject, input, Renderer2 } from '@angular/core';
22
import { Breakpoints, Colors } from '../coreui.types';
3-
import { ITable } from './table.type';
43

54
@Directive({
65
selector: 'table[cTable]',
7-
host: { class: 'table' }
6+
exportAs: 'cTable',
7+
host: {
8+
class: 'table',
9+
'[class]': 'hostClasses()'
10+
}
811
})
9-
export class TableDirective implements ITable, OnInit {
12+
export class TableDirective {
1013
readonly #renderer = inject(Renderer2);
1114
readonly #hostElement = inject(ElementRef);
1215

1316
/**
1417
* Set the vertical alignment.
15-
* @type string
18+
* @return string
1619
* @values 'bottom' | 'middle' | 'top'
1720
*/
18-
@Input() align?: 'bottom' | 'middle' | 'top';
21+
readonly align = input<'bottom' | 'middle' | 'top'>();
1922

2023
/**
2124
* Sets the border color of the component to one of CoreUI’s themed colors.
22-
* @type Colors
25+
* @return Colors
2326
*/
24-
@Input() borderColor?: Colors;
27+
readonly borderColor = input<Colors>();
2528

2629
/**
2730
* Add borders on all sides of the table and cells.
28-
* @type boolean
31+
* @return boolean
2932
*/
30-
@Input({ transform: booleanAttribute }) bordered: string | boolean = false;
33+
readonly bordered = input(false, { transform: booleanAttribute });
3134

3235
/**
3336
* Remove borders on all sides of the table and cells.
34-
* @type boolean
37+
* @return boolean
3538
*/
36-
@Input({ transform: booleanAttribute }) borderless: string | boolean = false;
39+
readonly borderless = input(false, { transform: booleanAttribute });
3740

3841
/**
3942
* Put the `<caption>` on the top of the table.
43+
* @return 'top'
4044
* @values 'top'
4145
*/
42-
@Input() caption?: 'top';
46+
readonly caption = input<'top'>();
4347

4448
/**
4549
* Sets the color context of the component to one of CoreUI’s themed colors.
46-
* @type Colors
50+
* @return Colors
4751
*/
48-
@Input() color?: Colors;
52+
readonly color = input<Colors>();
4953

5054
/**
5155
* Enable a hover state on table rows within table body.
52-
* @type boolean
56+
* @return boolean
5357
*/
54-
@Input({ transform: booleanAttribute }) hover: string | boolean = false;
58+
readonly hover = input(false, { transform: booleanAttribute });
5559

5660
/**
5761
* Make table responsive across all viewports or pick a maximum breakpoint with which to have a responsive table up to.
58-
* @type: {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'}
62+
* @values: {boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'}
5963
*/
60-
@Input() responsive?: boolean | Omit<Breakpoints, 'xs'>;
64+
readonly responsive = input<boolean | Omit<Breakpoints, 'xs'>>();
6165

6266
/**
6367
* Make table more compact by cutting all cell `padding` in half.
64-
* @type boolean
68+
* @return boolean
6569
*/
66-
@Input({ transform: booleanAttribute }) small: string | boolean = false;
70+
readonly small = input(false, { transform: booleanAttribute });
6771

6872
/**
6973
* Add zebra-striping to any table row within the table body.
70-
* @type boolean
74+
* @return boolean
7175
*/
72-
@Input({ transform: booleanAttribute }) striped: string | boolean = false;
76+
readonly striped = input(false, { transform: booleanAttribute });
7377

7478
/**
7579
* Add zebra-striping to any table column.
76-
* @type boolean
80+
* @return boolean
7781
* @since 4.2.4
7882
*/
79-
@Input({ transform: booleanAttribute }) stripedColumns: string | boolean = false;
83+
readonly stripedColumns = input(false, { transform: booleanAttribute });
84+
85+
readonly hostClasses = computed(() => {
86+
const align = this.align();
87+
const caption = this.caption();
88+
const borderColor = this.borderColor();
89+
const bordered = this.bordered();
90+
const borderless = this.borderless();
91+
const color = this.color();
92+
const hover = this.hover();
93+
const small = this.small();
94+
const striped = this.striped();
95+
const stripedColumns = this.stripedColumns();
8096

81-
@HostBinding('class')
82-
get hostClasses(): any {
8397
return {
8498
table: true,
85-
[`align-${this.align}`]: !!this.align,
86-
[`caption-${this.caption}`]: !!this.caption,
87-
[`border-${this.borderColor}`]: !!this.borderColor,
88-
'table-bordered': this.bordered,
89-
'table-borderless': this.borderless,
90-
[`table-${this.color}`]: !!this.color,
91-
'table-hover': this.hover,
92-
'table-sm': this.small,
93-
'table-striped': this.striped,
94-
'table-striped-columns': this.stripedColumns
99+
[`align-${align}`]: !!align,
100+
[`caption-${caption}`]: !!caption,
101+
[`border-${borderColor}`]: !!borderColor,
102+
'table-bordered': bordered,
103+
'table-borderless': borderless,
104+
[`table-${color}`]: !!color,
105+
'table-hover': hover,
106+
'table-sm': small,
107+
'table-striped': striped,
108+
'table-striped-columns': stripedColumns
95109
};
96-
}
110+
});
97111

98-
ngOnInit(): void {
99-
this.setResponsiveWrapper();
100-
}
101-
102-
// todo
103-
setResponsiveWrapper(): void {
104-
if (!!this.responsive) {
112+
readonly #responsiveWrapperEffect = effect(() => {
113+
const responsive = this.responsive();
114+
if (!!responsive) {
105115
const nativeElement: HTMLElement = this.#hostElement.nativeElement;
106116
const wrapper = this.#renderer.createElement('div');
107-
const className = this.responsive === true ? 'table-responsive' : `table-responsive-${this.responsive}`;
117+
const className = responsive === true ? 'table-responsive' : `table-responsive-${responsive}`;
108118
this.#renderer.addClass(wrapper, className);
109119
const parentNode = this.#renderer.parentNode(nativeElement);
110120
this.#renderer.appendChild(parentNode, wrapper);
111121
this.#renderer.insertBefore(parentNode, wrapper, nativeElement);
112122
this.#renderer.appendChild(wrapper, nativeElement);
113123
}
114-
}
124+
});
115125
}

0 commit comments

Comments
 (0)