Skip to content

Commit 2dc796c

Browse files
feat(Table): column widths can be defined by consumer
BREAKING CHANGE: - `TsColumn` definitions must be passed to `TsTable`. - `minWidth` support has been removed in favor of `TsColumn` definitions. ISSUES CLOSED: #1617
1 parent 9306553 commit 2dc796c

15 files changed

+450
-337
lines changed

demo/app/components/table/table.component.html

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,22 @@
1717
<div class="example-container">
1818
<ts-table
1919
[dataSource]="dataSource"
20+
[columns]="resizableColumns"
2021
tsSort
2122
tsVerticalSpacing
23+
#myTable="tsTable"
2224
>
2325

24-
<ng-container tsColumnDef="created" noWrap="true" minWidth="200px">
25-
<ts-header-cell *tsHeaderCellDef ts-sort-header>
26-
Created
26+
<ng-container tsColumnDef="title" sticky>
27+
<ts-header-cell *tsHeaderCellDef>
28+
Title
2729
</ts-header-cell>
2830
<ts-cell *tsCellDef="let item">
29-
{{ item.created_at | date:"shortDate" }}
31+
{{ item.title }}
3032
</ts-cell>
3133
</ng-container>
3234

33-
<ng-container tsColumnDef="updated" noWrap="true" minWidth="200px" sticky>
35+
<ng-container tsColumnDef="updated" noWrap="true">
3436
<ts-header-cell *tsHeaderCellDef ts-sort-header>
3537
Updated
3638
</ts-header-cell>
@@ -39,92 +41,105 @@
3941
</ts-cell>
4042
</ng-container>
4143

42-
<ng-container tsColumnDef="number" noWrap="true" minWidth="100px">
43-
<ts-header-cell *tsHeaderCellDef>
44-
Number
44+
<ng-container tsColumnDef="comments" noWrap="true">
45+
<ts-header-cell *tsHeaderCellDef ts-sort-header>
46+
Comments
4547
</ts-header-cell>
4648
<ts-cell *tsCellDef="let item">
47-
{{ item.number }}
49+
{{ item.comments }}
4850
</ts-cell>
4951
</ng-container>
5052

51-
<ng-container tsColumnDef="title" minWidth="400px">
52-
<ts-header-cell *tsHeaderCellDef>
53-
Title
53+
<ng-container tsColumnDef="assignee" noWrap="true">
54+
<ts-header-cell *tsHeaderCellDef ts-sort-header>
55+
Assignee
5456
</ts-header-cell>
5557
<ts-cell *tsCellDef="let item">
56-
{{ item.title }}
58+
{{ item.login }}
5759
</ts-cell>
5860
</ng-container>
5961

60-
<ng-container tsColumnDef="body" minWidth="500px">
62+
<ng-container tsColumnDef="number" noWrap="true" alignment="right">
6163
<ts-header-cell *tsHeaderCellDef>
62-
Body
64+
Number
6365
</ts-header-cell>
6466
<ts-cell *tsCellDef="let item">
65-
<span [innerHTML]="item.body"></span>
67+
{{ item.number }}
6668
</ts-cell>
6769
</ng-container>
6870

69-
<ng-container tsColumnDef="state" noWrap="true" minWidth="200px">
71+
<ng-container tsColumnDef="labels">
7072
<ts-header-cell *tsHeaderCellDef>
71-
State
73+
Labels
7274
</ts-header-cell>
7375
<ts-cell *tsCellDef="let item">
74-
{{ item.state }}
76+
<span *ngFor="let l of item.labels">
77+
{{ l.name }},
78+
</span>
7579
</ts-cell>
7680
</ng-container>
7781

78-
<ng-container tsColumnDef="comments" noWrap="true" alignment="right" minWidth="200px">
82+
<ng-container tsColumnDef="created" noWrap="true">
7983
<ts-header-cell *tsHeaderCellDef ts-sort-header>
80-
Comments
84+
Created
8185
</ts-header-cell>
8286
<ts-cell *tsCellDef="let item">
83-
{{ item.comments }}
87+
{{ item.created_at | date:"shortDate" }}
8488
</ts-cell>
8589
</ng-container>
8690

87-
<ng-container tsColumnDef="assignee" noWrap="true" minWidth="200px">
88-
<ts-header-cell *tsHeaderCellDef ts-sort-header>
89-
Assignee
91+
<ng-container tsColumnDef="body">
92+
<ts-header-cell *tsHeaderCellDef>
93+
Body
9094
</ts-header-cell>
9195
<ts-cell *tsCellDef="let item">
92-
{{ item.login }}
96+
<span class="truncate" [innerHTML]="sanitize(item.body)"></span>
9397
</ts-cell>
9498
</ng-container>
9599

96-
<ng-container tsColumnDef="labels" minWidth="200px">
100+
<ng-container tsColumnDef="state" noWrap="true">
97101
<ts-header-cell *tsHeaderCellDef>
98-
Labels
102+
State
99103
</ts-header-cell>
100104
<ts-cell *tsCellDef="let item">
101-
<span *ngFor="let l of item.labels">
102-
{{ l.name }},
103-
</span>
105+
{{ item.state }}
104106
</ts-cell>
105107
</ng-container>
106108

107-
<ng-container tsColumnDef="id" minWidth="200px" stickyEnd>
109+
<ng-container tsColumnDef="id" alignment="right">
108110
<ts-header-cell *tsHeaderCellDef>
109111
ID
110112
</ts-header-cell>
111113
<ts-cell *tsCellDef="let item">
112-
{{ item.id }},
114+
{{ item.id }}
115+
</ts-cell>
116+
</ng-container>
117+
118+
<ng-container tsColumnDef="html_url" noWrap="true" stickyEnd>
119+
<ts-header-cell *tsHeaderCellDef>
120+
View
121+
</ts-header-cell>
122+
<ts-cell *tsCellDef="let item">
123+
<a href="{{ item.html_url }}">
124+
<ts-icon>open_in_new</ts-icon>
125+
</a>
113126
</ts-cell>
114127
</ng-container>
115128

116-
<ts-header-row *tsHeaderRowDef="displayedColumns; sticky: true"></ts-header-row>
129+
<ts-header-row *tsHeaderRowDef="myTable.columnNames; sticky: true"></ts-header-row>
117130

118-
<ts-row *tsRowDef="let row; columns: displayedColumns;">
131+
<ts-row *tsRowDef="let row; columns: myTable.columnNames;">
119132
</ts-row>
120133

121134
</ts-table>
122135
</div>
123136

124-
<ts-paginator
125-
[totalRecords]="resultsLength"
126-
recordCountTooHighMessage="Please refine your filters."
127-
(pageSelect)="onPageSelect($event)"
128-
(recordsPerPageChange)="perPageChange($event)"
129-
></ts-paginator>
137+
<div fxLayout="row" fxLayoutAlign="end start">
138+
<ts-paginator
139+
[totalRecords]="resultsLength"
140+
recordCountTooHighMessage="Please refine your filters."
141+
(pageSelect)="onPageSelect($event)"
142+
(recordsPerPageChange)="perPageChange($event)"
143+
></ts-paginator>
144+
</div>
130145

demo/app/components/table/table.component.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@
66
overflow: auto;
77
@include visible-scrollbars;
88
}
9+
10+
.truncate {
11+
display: block;
12+
max-height: 100px;
13+
overflow: hidden;
14+
text-overflow: ellipsis;
15+
}

demo/app/components/table/table.component.ts

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import {
44
Component,
55
ViewChild,
66
} from '@angular/core';
7+
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
78
import {
89
TsPaginatorComponent,
910
TsPaginatorMenuItem,
1011
} from '@terminus/ui/paginator';
1112
import { TsSortDirective } from '@terminus/ui/sort';
12-
import { TsTableDataSource } from '@terminus/ui/table';
13+
import {
14+
TsColumn,
15+
TsTableDataSource,
16+
} from '@terminus/ui/table';
1317
import {
1418
merge,
1519
Observable,
@@ -76,10 +80,14 @@ const COLUMNS_SOURCE_GITHUB = [
7680

7781
export interface GithubApi {
7882
items: GithubIssue[];
83+
// NOTE: Format controlled by GitHub
84+
// eslint-disable-next-line camelcase
7985
total_count: number;
8086
}
8187

8288
export interface GithubIssue {
89+
// NOTE: Format controlled by GitHub
90+
// eslint-disable-next-line camelcase
8391
created_at: string;
8492
number: string;
8593
state: string;
@@ -92,11 +100,10 @@ export interface GithubIssue {
92100
export class ExampleHttpDao {
93101
constructor(private http: HttpClient) {}
94102

95-
getRepoIssues(sort: string, order: string, page: number, perPage: number): Observable<GithubApi> {
96-
const href = 'https://api.github.com/search/issues';
103+
public getRepoIssues(sort: string, order: string, page: number, perPage: number): Observable<GithubApi> {
104+
const href = `https://api.github.com/search/issues`;
97105
const requestUrl = `${href}?q=repo:GetTerminus/terminus-ui`;
98106
const requestParams = `&sort=${sort}&order=${order}&page=${page + 1}&per_page=${perPage}`;
99-
100107
return this.http.get<GithubApi>(`${requestUrl}${requestParams}`);
101108
}
102109
}
@@ -108,35 +115,61 @@ export class ExampleHttpDao {
108115
styleUrls: ['./table.component.scss'],
109116
})
110117
export class TableComponent implements AfterViewInit {
111-
allColumns = COLUMNS_SOURCE_GITHUB.slice(0);
112-
displayedColumns: string[] = [
118+
public allColumns = COLUMNS_SOURCE_GITHUB.slice(0);
119+
public displayedColumns = [
113120
'title',
114121
'updated',
115122
'comments',
116123
'assignee',
117124
'number',
118125
'labels',
119126
'created',
120-
'id',
121127
'body',
128+
'id',
129+
'html_url',
130+
];
131+
public exampleDatabase!: ExampleHttpDao;
132+
public dataSource = new TsTableDataSource<GithubIssue>();
133+
public resultsLength = 0;
134+
public resizableColumns: TsColumn[] = [
135+
{
136+
name: 'title',
137+
width: '400px',
138+
},
139+
{ name: 'updated' },
140+
{ name: 'comments' },
141+
{
142+
name: 'assignee',
143+
width: '160px',
144+
},
145+
{ name: 'number' },
146+
{
147+
name: 'labels',
148+
width: '260px',
149+
},
150+
{ name: 'created' },
151+
{ name: 'id' },
152+
{
153+
name: 'body',
154+
width: '500px',
155+
},
156+
{ name: 'html_url' },
122157
];
123-
exampleDatabase!: ExampleHttpDao;
124-
dataSource: TsTableDataSource<GithubIssue> = new TsTableDataSource();
125-
resultsLength = 0;
126158

127-
@ViewChild(TsSortDirective, {static: true})
128-
sort!: TsSortDirective;
159+
@ViewChild(TsSortDirective, { static: true })
160+
public sort!: TsSortDirective;
129161

130-
@ViewChild(TsPaginatorComponent, {static: true})
131-
paginator!: TsPaginatorComponent;
162+
@ViewChild(TsPaginatorComponent, { static: true })
163+
public readonly paginator!: TsPaginatorComponent;
132164

133165

134166
constructor(
167+
private domSanitizer: DomSanitizer,
135168
private http: HttpClient,
136169
) {}
137170

138171

139-
ngAfterViewInit(): void {
172+
public ngAfterViewInit(): void {
140173
this.exampleDatabase = new ExampleHttpDao(this.http);
141174

142175
// If the user changes the sort order, reset back to the first page.
@@ -171,12 +204,16 @@ export class TableComponent implements AfterViewInit {
171204
}
172205

173206

174-
perPageChange(e: number): void {
207+
public perPageChange(e: number): void {
175208
console.log('DEMO records per page changed: ', e);
176209
}
177210

178-
onPageSelect(e: TsPaginatorMenuItem): void {
211+
public onPageSelect(e: TsPaginatorMenuItem): void {
179212
console.log('DEMO page selected: ', e);
180213
}
181214

215+
public sanitize(content): SafeHtml {
216+
return this.domSanitizer.bypassSecurityTrustHtml(content);
217+
}
218+
182219
}

demo/app/components/table/table.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
33
import { FlexLayoutModule } from '@angular/flex-layout';
44
import { FormsModule } from '@angular/forms';
55
import { TsCardModule } from '@terminus/ui/card';
6+
import { TsIconModule } from '@terminus/ui/icon';
67
import { TsOptionModule } from '@terminus/ui/option';
78
import { TsPaginatorModule } from '@terminus/ui/paginator';
89
import { TsSelectModule } from '@terminus/ui/select';
@@ -21,6 +22,7 @@ import { TableComponent } from './table.component';
2122
FormsModule,
2223
TableRoutingModule,
2324
TsCardModule,
25+
TsIconModule,
2426
TsOptionModule,
2527
TsPaginatorModule,
2628
TsSelectModule,

terminus-ui/sort/src/sort-header.component.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ import {
1313
Optional,
1414
ViewEncapsulation,
1515
} from '@angular/core';
16-
import {
17-
CanDisable,
18-
mixinDisabled,
19-
} from '@angular/material/core';
16+
import { CanDisable } from '@angular/material/core';
2017
import { coerceBooleanProperty } from '@terminus/ngx-tools/coercion';
2118
import { isBoolean } from '@terminus/ngx-tools/type-guards';
2219
import { untilComponentDestroyed } from '@terminus/ngx-tools/utilities';
@@ -48,12 +45,10 @@ import {
4845
* <example-url>https://getterminus.github.io/ui-demos-release/components/table</example-url>
4946
*/
5047
@Component({
51-
// NOTE(B$): This component needs to be added to another component so we need a non-element
52-
// selector
48+
// NOTE: This component needs to be added to another component so we need a non-element selector
5349
// tslint:disable: component-selector
5450
selector: '[ts-sort-header]',
5551
// tslint:enable: component-selector
56-
exportAs: 'tsSortHeader',
5752
templateUrl: './sort-header.component.html',
5853
styleUrls: ['./sort-header.component.scss'],
5954
host: {
@@ -63,8 +58,6 @@ import {
6358
'(click)': '_handleClick()',
6459
},
6560
preserveWhitespaces: false,
66-
encapsulation: ViewEncapsulation.None,
67-
changeDetection: ChangeDetectionStrategy.OnPush,
6861
// NOTE: @Inputs are defined here rather than using decorators since we are extending the @Inputs of the base class
6962
// tslint:disable-next-line:no-inputs-metadata-property
7063
inputs: ['disabled'],
@@ -74,6 +67,9 @@ import {
7467
tsSortAnimations.rightPointer,
7568
tsSortAnimations.indicatorToggle,
7669
],
70+
changeDetection: ChangeDetectionStrategy.OnPush,
71+
encapsulation: ViewEncapsulation.None,
72+
exportAs: 'tsSortHeader',
7773
})
7874
export class TsSortHeaderComponent implements TsSortableItem, CanDisable, OnInit, OnDestroy {
7975
public disabled = false;

terminus-ui/table/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
{
22
"ngPackage": {
33
"lib": {
4-
"entryFile": "src/public-api.ts"
4+
"entryFile": "src/public-api.ts",
5+
"umdModuleIds": {
6+
"@terminus/ngx-tools/type-guards": "terminus.ngxTools.type-guards"
7+
}
58
}
69
}
710
}

0 commit comments

Comments
 (0)