/
row.ts
308 lines (266 loc) · 9.96 KB
/
row.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {BooleanInput} from '@angular/cdk/coercion';
import {
ChangeDetectionStrategy,
Component,
Directive,
IterableChanges,
IterableDiffer,
IterableDiffers,
OnChanges,
OnDestroy,
SimpleChanges,
TemplateRef,
ViewContainerRef,
ViewEncapsulation,
Inject,
Optional
} from '@angular/core';
import {CanStick, CanStickCtor, mixinHasStickyInput} from './can-stick';
import {CdkCellDef, CdkColumnDef} from './cell';
import {CDK_TABLE} from './tokens';
/**
* The row template that can be used by the mat-table. Should not be used outside of the
* material library.
*/
export const CDK_ROW_TEMPLATE = `<ng-container cdkCellOutlet></ng-container>`;
/**
* Base class for the CdkHeaderRowDef and CdkRowDef that handles checking their columns inputs
* for changes and notifying the table.
*/
export abstract class BaseRowDef implements OnChanges {
/** The columns to be displayed on this row. */
columns: Iterable<string>;
/** Differ used to check if any changes were made to the columns. */
protected _columnsDiffer: IterableDiffer<any>;
constructor(
/** @docs-private */ public template: TemplateRef<any>, protected _differs: IterableDiffers) {
}
ngOnChanges(changes: SimpleChanges): void {
// Create a new columns differ if one does not yet exist. Initialize it based on initial value
// of the columns property or an empty array if none is provided.
if (!this._columnsDiffer) {
const columns = (changes['columns'] && changes['columns'].currentValue) || [];
this._columnsDiffer = this._differs.find(columns).create();
this._columnsDiffer.diff(columns);
}
}
/**
* Returns the difference between the current columns and the columns from the last diff, or null
* if there is no difference.
*/
getColumnsDiff(): IterableChanges<any>|null {
return this._columnsDiffer.diff(this.columns);
}
/** Gets this row def's relevant cell template from the provided column def. */
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
if (this instanceof CdkHeaderRowDef) {
return column.headerCell.template;
}
if (this instanceof CdkFooterRowDef) {
return column.footerCell.template;
} else {
return column.cell.template;
}
}
}
// Boilerplate for applying mixins to CdkHeaderRowDef.
/** @docs-private */
class CdkHeaderRowDefBase extends BaseRowDef {}
const _CdkHeaderRowDefBase: CanStickCtor&typeof CdkHeaderRowDefBase =
mixinHasStickyInput(CdkHeaderRowDefBase);
/**
* Header row definition for the CDK table.
* Captures the header row's template and other header properties such as the columns to display.
*/
@Directive({
selector: '[cdkHeaderRowDef]',
inputs: ['columns: cdkHeaderRowDef', 'sticky: cdkHeaderRowDefSticky'],
})
export class CdkHeaderRowDef extends _CdkHeaderRowDefBase implements CanStick, OnChanges {
constructor(
template: TemplateRef<any>,
_differs: IterableDiffers,
@Inject(CDK_TABLE) @Optional() public _table?: any) {
super(template, _differs);
}
// Prerender fails to recognize that ngOnChanges in a part of this class through inheritance.
// Explicitly define it so that the method is called as part of the Angular lifecycle.
ngOnChanges(changes: SimpleChanges): void {
super.ngOnChanges(changes);
}
static ngAcceptInputType_sticky: BooleanInput;
}
// Boilerplate for applying mixins to CdkFooterRowDef.
/** @docs-private */
class CdkFooterRowDefBase extends BaseRowDef {}
const _CdkFooterRowDefBase: CanStickCtor&typeof CdkFooterRowDefBase =
mixinHasStickyInput(CdkFooterRowDefBase);
/**
* Footer row definition for the CDK table.
* Captures the footer row's template and other footer properties such as the columns to display.
*/
@Directive({
selector: '[cdkFooterRowDef]',
inputs: ['columns: cdkFooterRowDef', 'sticky: cdkFooterRowDefSticky'],
})
export class CdkFooterRowDef extends _CdkFooterRowDefBase implements CanStick, OnChanges {
constructor(
template: TemplateRef<any>,
_differs: IterableDiffers,
@Inject(CDK_TABLE) @Optional() public _table?: any) {
super(template, _differs);
}
// Prerender fails to recognize that ngOnChanges in a part of this class through inheritance.
// Explicitly define it so that the method is called as part of the Angular lifecycle.
ngOnChanges(changes: SimpleChanges): void {
super.ngOnChanges(changes);
}
static ngAcceptInputType_sticky: BooleanInput;
}
/**
* Data row definition for the CDK table.
* Captures the header row's template and other row properties such as the columns to display and
* a when predicate that describes when this row should be used.
*/
@Directive({
selector: '[cdkRowDef]',
inputs: ['columns: cdkRowDefColumns', 'when: cdkRowDefWhen'],
})
export class CdkRowDef<T> extends BaseRowDef {
/**
* Function that should return true if this row template should be used for the provided index
* and row data. If left undefined, this row will be considered the default row template to use
* when no other when functions return true for the data.
* For every row, there must be at least one when function that passes or an undefined to default.
*/
when: (index: number, rowData: T) => boolean;
// TODO(andrewseguin): Add an input for providing a switch function to determine
// if this template should be used.
constructor(
template: TemplateRef<any>,
_differs: IterableDiffers,
@Inject(CDK_TABLE) @Optional() public _table?: any) {
super(template, _differs);
}
}
/** Context provided to the row cells when `multiTemplateDataRows` is false */
export interface CdkCellOutletRowContext<T> {
/** Data for the row that this cell is located within. */
$implicit?: T;
/** Index of the data object in the provided data array. */
index?: number;
/** Length of the number of total rows. */
count?: number;
/** True if this cell is contained in the first row. */
first?: boolean;
/** True if this cell is contained in the last row. */
last?: boolean;
/** True if this cell is contained in a row with an even-numbered index. */
even?: boolean;
/** True if this cell is contained in a row with an odd-numbered index. */
odd?: boolean;
}
/**
* Context provided to the row cells when `multiTemplateDataRows` is true. This context is the same
* as CdkCellOutletRowContext except that the single `index` value is replaced by `dataIndex` and
* `renderIndex`.
*/
export interface CdkCellOutletMultiRowContext<T> {
/** Data for the row that this cell is located within. */
$implicit?: T;
/** Index of the data object in the provided data array. */
dataIndex?: number;
/** Index location of the rendered row that this cell is located within. */
renderIndex?: number;
/** Length of the number of total rows. */
count?: number;
/** True if this cell is contained in the first row. */
first?: boolean;
/** True if this cell is contained in the last row. */
last?: boolean;
/** True if this cell is contained in a row with an even-numbered index. */
even?: boolean;
/** True if this cell is contained in a row with an odd-numbered index. */
odd?: boolean;
}
/**
* Outlet for rendering cells inside of a row or header row.
* @docs-private
*/
@Directive({selector: '[cdkCellOutlet]'})
export class CdkCellOutlet implements OnDestroy {
/** The ordered list of cells to render within this outlet's view container */
cells: CdkCellDef[];
/** The data context to be provided to each cell */
context: any;
/**
* Static property containing the latest constructed instance of this class.
* Used by the CDK table when each CdkHeaderRow and CdkRow component is created using
* createEmbeddedView. After one of these components are created, this property will provide
* a handle to provide that component's cells and context. After init, the CdkCellOutlet will
* construct the cells with the provided context.
*/
static mostRecentCellOutlet: CdkCellOutlet|null = null;
constructor(public _viewContainer: ViewContainerRef) {
CdkCellOutlet.mostRecentCellOutlet = this;
}
ngOnDestroy() {
// If this was the last outlet being rendered in the view, remove the reference
// from the static property after it has been destroyed to avoid leaking memory.
if (CdkCellOutlet.mostRecentCellOutlet === this) {
CdkCellOutlet.mostRecentCellOutlet = null;
}
}
}
/** Header template container that contains the cell outlet. Adds the right class and role. */
@Component({
selector: 'cdk-header-row, tr[cdk-header-row]',
template: CDK_ROW_TEMPLATE,
host: {
'class': 'cdk-header-row',
'role': 'row',
},
// See note on CdkTable for explanation on why this uses the default change detection strategy.
// tslint:disable-next-line:validate-decorators
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None,
})
export class CdkHeaderRow {
}
/** Footer template container that contains the cell outlet. Adds the right class and role. */
@Component({
selector: 'cdk-footer-row, tr[cdk-footer-row]',
template: CDK_ROW_TEMPLATE,
host: {
'class': 'cdk-footer-row',
'role': 'row',
},
// See note on CdkTable for explanation on why this uses the default change detection strategy.
// tslint:disable-next-line:validate-decorators
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None,
})
export class CdkFooterRow {
}
/** Data row template container that contains the cell outlet. Adds the right class and role. */
@Component({
selector: 'cdk-row, tr[cdk-row]',
template: CDK_ROW_TEMPLATE,
host: {
'class': 'cdk-row',
'role': 'row',
},
// See note on CdkTable for explanation on why this uses the default change detection strategy.
// tslint:disable-next-line:validate-decorators
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None,
})
export class CdkRow {
}