table.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /**
  2. * @license
  3. * Copyright Google LLC All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. import { CDK_TABLE_TEMPLATE, CdkTable, CdkCell, CdkCellDef, CdkColumnDef, CdkFooterCell, CdkFooterCellDef, CdkHeaderCell, CdkHeaderCellDef, CDK_ROW_TEMPLATE, CdkFooterRow, CdkFooterRowDef, CdkHeaderRow, CdkHeaderRowDef, CdkRow, CdkRowDef, CdkTextColumn, CdkTableModule, DataSource } from '@angular/cdk/table';
  9. import { ChangeDetectionStrategy, Component, ViewEncapsulation, Directive, ElementRef, Input, NgModule } from '@angular/core';
  10. import { CommonModule } from '@angular/common';
  11. import { MatCommonModule } from '@angular/material/core';
  12. import { _isNumberValue } from '@angular/cdk/coercion';
  13. import { BehaviorSubject, combineLatest, merge, of, Subscription, Subject } from 'rxjs';
  14. import { map } from 'rxjs/operators';
  15. /**
  16. * @fileoverview added by tsickle
  17. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  18. */
  19. /**
  20. * Wrapper for the CdkTable with Material design styles.
  21. * @template T
  22. */
  23. class MatTable extends CdkTable {
  24. constructor() {
  25. super(...arguments);
  26. /**
  27. * Overrides the sticky CSS class set by the `CdkTable`.
  28. */
  29. this.stickyCssClass = 'mat-table-sticky';
  30. }
  31. }
  32. MatTable.decorators = [
  33. { type: Component, args: [{selector: 'mat-table, table[mat-table]',
  34. exportAs: 'matTable',
  35. template: CDK_TABLE_TEMPLATE,
  36. styles: ["mat-table{display:block}mat-header-row{min-height:56px}mat-footer-row,mat-row{min-height:48px}mat-footer-row,mat-header-row,mat-row{display:flex;border-width:0;border-bottom-width:1px;border-style:solid;align-items:center;box-sizing:border-box}mat-footer-row::after,mat-header-row::after,mat-row::after{display:inline-block;min-height:inherit;content:''}mat-cell:first-of-type,mat-footer-cell:first-of-type,mat-header-cell:first-of-type{padding-left:24px}[dir=rtl] mat-cell:first-of-type,[dir=rtl] mat-footer-cell:first-of-type,[dir=rtl] mat-header-cell:first-of-type{padding-left:0;padding-right:24px}mat-cell:last-of-type,mat-footer-cell:last-of-type,mat-header-cell:last-of-type{padding-right:24px}[dir=rtl] mat-cell:last-of-type,[dir=rtl] mat-footer-cell:last-of-type,[dir=rtl] mat-header-cell:last-of-type{padding-right:0;padding-left:24px}mat-cell,mat-footer-cell,mat-header-cell{flex:1;display:flex;align-items:center;overflow:hidden;word-wrap:break-word;min-height:inherit}table.mat-table{border-spacing:0}tr.mat-header-row{height:56px}tr.mat-footer-row,tr.mat-row{height:48px}th.mat-header-cell{text-align:left}[dir=rtl] th.mat-header-cell{text-align:right}td.mat-cell,td.mat-footer-cell,th.mat-header-cell{padding:0;border-bottom-width:1px;border-bottom-style:solid}td.mat-cell:first-of-type,td.mat-footer-cell:first-of-type,th.mat-header-cell:first-of-type{padding-left:24px}[dir=rtl] td.mat-cell:first-of-type,[dir=rtl] td.mat-footer-cell:first-of-type,[dir=rtl] th.mat-header-cell:first-of-type{padding-left:0;padding-right:24px}td.mat-cell:last-of-type,td.mat-footer-cell:last-of-type,th.mat-header-cell:last-of-type{padding-right:24px}[dir=rtl] td.mat-cell:last-of-type,[dir=rtl] td.mat-footer-cell:last-of-type,[dir=rtl] th.mat-header-cell:last-of-type{padding-right:0;padding-left:24px}"],
  37. host: {
  38. 'class': 'mat-table',
  39. },
  40. providers: [{ provide: CdkTable, useExisting: MatTable }],
  41. encapsulation: ViewEncapsulation.None,
  42. // See note on CdkTable for explanation on why this uses the default change detection strategy.
  43. // tslint:disable-next-line:validate-decorators
  44. changeDetection: ChangeDetectionStrategy.Default,
  45. },] },
  46. ];
  47. /**
  48. * @fileoverview added by tsickle
  49. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  50. */
  51. /**
  52. * Cell definition for the mat-table.
  53. * Captures the template of a column's data row cell as well as cell-specific properties.
  54. */
  55. class MatCellDef extends CdkCellDef {
  56. }
  57. MatCellDef.decorators = [
  58. { type: Directive, args: [{
  59. selector: '[matCellDef]',
  60. providers: [{ provide: CdkCellDef, useExisting: MatCellDef }]
  61. },] },
  62. ];
  63. /**
  64. * Header cell definition for the mat-table.
  65. * Captures the template of a column's header cell and as well as cell-specific properties.
  66. */
  67. class MatHeaderCellDef extends CdkHeaderCellDef {
  68. }
  69. MatHeaderCellDef.decorators = [
  70. { type: Directive, args: [{
  71. selector: '[matHeaderCellDef]',
  72. providers: [{ provide: CdkHeaderCellDef, useExisting: MatHeaderCellDef }]
  73. },] },
  74. ];
  75. /**
  76. * Footer cell definition for the mat-table.
  77. * Captures the template of a column's footer cell and as well as cell-specific properties.
  78. */
  79. class MatFooterCellDef extends CdkFooterCellDef {
  80. }
  81. MatFooterCellDef.decorators = [
  82. { type: Directive, args: [{
  83. selector: '[matFooterCellDef]',
  84. providers: [{ provide: CdkFooterCellDef, useExisting: MatFooterCellDef }]
  85. },] },
  86. ];
  87. /**
  88. * Column definition for the mat-table.
  89. * Defines a set of cells available for a table column.
  90. */
  91. class MatColumnDef extends CdkColumnDef {
  92. }
  93. MatColumnDef.decorators = [
  94. { type: Directive, args: [{
  95. selector: '[matColumnDef]',
  96. providers: [
  97. { provide: CdkColumnDef, useExisting: MatColumnDef },
  98. { provide: 'MAT_SORT_HEADER_COLUMN_DEF', useExisting: MatColumnDef }
  99. ],
  100. },] },
  101. ];
  102. MatColumnDef.propDecorators = {
  103. name: [{ type: Input, args: ['matColumnDef',] }],
  104. sticky: [{ type: Input }],
  105. stickyEnd: [{ type: Input }]
  106. };
  107. /**
  108. * Header cell template container that adds the right classes and role.
  109. */
  110. class MatHeaderCell extends CdkHeaderCell {
  111. /**
  112. * @param {?} columnDef
  113. * @param {?} elementRef
  114. */
  115. constructor(columnDef, elementRef) {
  116. super(columnDef, elementRef);
  117. elementRef.nativeElement.classList.add(`mat-column-${columnDef.cssClassFriendlyName}`);
  118. }
  119. }
  120. MatHeaderCell.decorators = [
  121. { type: Directive, args: [{
  122. selector: 'mat-header-cell, th[mat-header-cell]',
  123. host: {
  124. 'class': 'mat-header-cell',
  125. 'role': 'columnheader',
  126. },
  127. },] },
  128. ];
  129. /** @nocollapse */
  130. MatHeaderCell.ctorParameters = () => [
  131. { type: CdkColumnDef },
  132. { type: ElementRef }
  133. ];
  134. /**
  135. * Footer cell template container that adds the right classes and role.
  136. */
  137. class MatFooterCell extends CdkFooterCell {
  138. /**
  139. * @param {?} columnDef
  140. * @param {?} elementRef
  141. */
  142. constructor(columnDef, elementRef) {
  143. super(columnDef, elementRef);
  144. elementRef.nativeElement.classList.add(`mat-column-${columnDef.cssClassFriendlyName}`);
  145. }
  146. }
  147. MatFooterCell.decorators = [
  148. { type: Directive, args: [{
  149. selector: 'mat-footer-cell, td[mat-footer-cell]',
  150. host: {
  151. 'class': 'mat-footer-cell',
  152. 'role': 'gridcell',
  153. },
  154. },] },
  155. ];
  156. /** @nocollapse */
  157. MatFooterCell.ctorParameters = () => [
  158. { type: CdkColumnDef },
  159. { type: ElementRef }
  160. ];
  161. /**
  162. * Cell template container that adds the right classes and role.
  163. */
  164. class MatCell extends CdkCell {
  165. /**
  166. * @param {?} columnDef
  167. * @param {?} elementRef
  168. */
  169. constructor(columnDef, elementRef) {
  170. super(columnDef, elementRef);
  171. elementRef.nativeElement.classList.add(`mat-column-${columnDef.cssClassFriendlyName}`);
  172. }
  173. }
  174. MatCell.decorators = [
  175. { type: Directive, args: [{
  176. selector: 'mat-cell, td[mat-cell]',
  177. host: {
  178. 'class': 'mat-cell',
  179. 'role': 'gridcell',
  180. },
  181. },] },
  182. ];
  183. /** @nocollapse */
  184. MatCell.ctorParameters = () => [
  185. { type: CdkColumnDef },
  186. { type: ElementRef }
  187. ];
  188. /**
  189. * @fileoverview added by tsickle
  190. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  191. */
  192. /**
  193. * Header row definition for the mat-table.
  194. * Captures the header row's template and other header properties such as the columns to display.
  195. */
  196. class MatHeaderRowDef extends CdkHeaderRowDef {
  197. }
  198. MatHeaderRowDef.decorators = [
  199. { type: Directive, args: [{
  200. selector: '[matHeaderRowDef]',
  201. providers: [{ provide: CdkHeaderRowDef, useExisting: MatHeaderRowDef }],
  202. inputs: ['columns: matHeaderRowDef', 'sticky: matHeaderRowDefSticky'],
  203. },] },
  204. ];
  205. /**
  206. * Footer row definition for the mat-table.
  207. * Captures the footer row's template and other footer properties such as the columns to display.
  208. */
  209. class MatFooterRowDef extends CdkFooterRowDef {
  210. }
  211. MatFooterRowDef.decorators = [
  212. { type: Directive, args: [{
  213. selector: '[matFooterRowDef]',
  214. providers: [{ provide: CdkFooterRowDef, useExisting: MatFooterRowDef }],
  215. inputs: ['columns: matFooterRowDef', 'sticky: matFooterRowDefSticky'],
  216. },] },
  217. ];
  218. /**
  219. * Data row definition for the mat-table.
  220. * Captures the data row's template and other properties such as the columns to display and
  221. * a when predicate that describes when this row should be used.
  222. * @template T
  223. */
  224. class MatRowDef extends CdkRowDef {
  225. }
  226. MatRowDef.decorators = [
  227. { type: Directive, args: [{
  228. selector: '[matRowDef]',
  229. providers: [{ provide: CdkRowDef, useExisting: MatRowDef }],
  230. inputs: ['columns: matRowDefColumns', 'when: matRowDefWhen'],
  231. },] },
  232. ];
  233. /**
  234. * Footer template container that contains the cell outlet. Adds the right class and role.
  235. */
  236. class MatHeaderRow extends CdkHeaderRow {
  237. }
  238. MatHeaderRow.decorators = [
  239. { type: Component, args: [{selector: 'mat-header-row, tr[mat-header-row]',
  240. template: CDK_ROW_TEMPLATE,
  241. host: {
  242. 'class': 'mat-header-row',
  243. 'role': 'row',
  244. },
  245. // See note on CdkTable for explanation on why this uses the default change detection strategy.
  246. // tslint:disable-next-line:validate-decorators
  247. changeDetection: ChangeDetectionStrategy.Default,
  248. encapsulation: ViewEncapsulation.None,
  249. exportAs: 'matHeaderRow',
  250. providers: [{ provide: CdkHeaderRow, useExisting: MatHeaderRow }],
  251. },] },
  252. ];
  253. /**
  254. * Footer template container that contains the cell outlet. Adds the right class and role.
  255. */
  256. class MatFooterRow extends CdkFooterRow {
  257. }
  258. MatFooterRow.decorators = [
  259. { type: Component, args: [{selector: 'mat-footer-row, tr[mat-footer-row]',
  260. template: CDK_ROW_TEMPLATE,
  261. host: {
  262. 'class': 'mat-footer-row',
  263. 'role': 'row',
  264. },
  265. // See note on CdkTable for explanation on why this uses the default change detection strategy.
  266. // tslint:disable-next-line:validate-decorators
  267. changeDetection: ChangeDetectionStrategy.Default,
  268. encapsulation: ViewEncapsulation.None,
  269. exportAs: 'matFooterRow',
  270. providers: [{ provide: CdkFooterRow, useExisting: MatFooterRow }],
  271. },] },
  272. ];
  273. /**
  274. * Data row template container that contains the cell outlet. Adds the right class and role.
  275. */
  276. class MatRow extends CdkRow {
  277. }
  278. MatRow.decorators = [
  279. { type: Component, args: [{selector: 'mat-row, tr[mat-row]',
  280. template: CDK_ROW_TEMPLATE,
  281. host: {
  282. 'class': 'mat-row',
  283. 'role': 'row',
  284. },
  285. // See note on CdkTable for explanation on why this uses the default change detection strategy.
  286. // tslint:disable-next-line:validate-decorators
  287. changeDetection: ChangeDetectionStrategy.Default,
  288. encapsulation: ViewEncapsulation.None,
  289. exportAs: 'matRow',
  290. providers: [{ provide: CdkRow, useExisting: MatRow }],
  291. },] },
  292. ];
  293. /**
  294. * @fileoverview added by tsickle
  295. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  296. */
  297. /**
  298. * Column that simply shows text content for the header and row cells. Assumes that the table
  299. * is using the native table implementation (`<table>`).
  300. *
  301. * By default, the name of this column will be the header text and data property accessor.
  302. * The header text can be overridden with the `headerText` input. Cell values can be overridden with
  303. * the `dataAccessor` input. Change the text justification to the start or end using the `justify`
  304. * input.
  305. * @template T
  306. */
  307. class MatTextColumn extends CdkTextColumn {
  308. }
  309. MatTextColumn.decorators = [
  310. { type: Component, args: [{selector: 'mat-text-column',
  311. template: `
  312. <ng-container matColumnDef>
  313. <th mat-header-cell *matHeaderCellDef [style.text-align]="justify">
  314. {{headerText}}
  315. </th>
  316. <td mat-cell *matCellDef="let data" [style.text-align]="justify">
  317. {{dataAccessor(data, name)}}
  318. </td>
  319. </ng-container>
  320. `,
  321. encapsulation: ViewEncapsulation.None,
  322. // Change detection is intentionally not set to OnPush. This component's template will be provided
  323. // to the table to be inserted into its view. This is problematic when change detection runs since
  324. // the bindings in this template will be evaluated _after_ the table's view is evaluated, which
  325. // mean's the template in the table's view will not have the updated value (and in fact will cause
  326. // an ExpressionChangedAfterItHasBeenCheckedError).
  327. // tslint:disable-next-line:validate-decorators
  328. changeDetection: ChangeDetectionStrategy.Default,
  329. },] },
  330. ];
  331. /**
  332. * @fileoverview added by tsickle
  333. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  334. */
  335. /** @type {?} */
  336. const EXPORTED_DECLARATIONS = [
  337. // Table
  338. MatTable,
  339. // Template defs
  340. MatHeaderCellDef,
  341. MatHeaderRowDef,
  342. MatColumnDef,
  343. MatCellDef,
  344. MatRowDef,
  345. MatFooterCellDef,
  346. MatFooterRowDef,
  347. // Cell directives
  348. MatHeaderCell,
  349. MatCell,
  350. MatFooterCell,
  351. // Row directives
  352. MatHeaderRow,
  353. MatRow,
  354. MatFooterRow,
  355. MatTextColumn,
  356. ];
  357. class MatTableModule {
  358. }
  359. MatTableModule.decorators = [
  360. { type: NgModule, args: [{
  361. imports: [
  362. CdkTableModule,
  363. CommonModule,
  364. MatCommonModule,
  365. ],
  366. exports: EXPORTED_DECLARATIONS,
  367. declarations: EXPORTED_DECLARATIONS,
  368. },] },
  369. ];
  370. /**
  371. * @fileoverview added by tsickle
  372. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  373. */
  374. /**
  375. * Corresponds to `Number.MAX_SAFE_INTEGER`. Moved out into a variable here due to
  376. * flaky browser support and the value not being defined in Closure's typings.
  377. * @type {?}
  378. */
  379. const MAX_SAFE_INTEGER = 9007199254740991;
  380. /**
  381. * Data source that accepts a client-side data array and includes native support of filtering,
  382. * sorting (using MatSort), and pagination (using MatPaginator).
  383. *
  384. * Allows for sort customization by overriding sortingDataAccessor, which defines how data
  385. * properties are accessed. Also allows for filter customization by overriding filterTermAccessor,
  386. * which defines how row data is converted to a string for filter matching.
  387. * @template T
  388. */
  389. class MatTableDataSource extends DataSource {
  390. /**
  391. * @param {?=} initialData
  392. */
  393. constructor(initialData = []) {
  394. super();
  395. /**
  396. * Stream emitting render data to the table (depends on ordered data changes).
  397. */
  398. this._renderData = new BehaviorSubject([]);
  399. /**
  400. * Stream that emits when a new filter string is set on the data source.
  401. */
  402. this._filter = new BehaviorSubject('');
  403. /**
  404. * Used to react to internal changes of the paginator that are made by the data source itself.
  405. */
  406. this._internalPageChanges = new Subject();
  407. /**
  408. * Subscription to the changes that should trigger an update to the table's rendered rows, such
  409. * as filtering, sorting, pagination, or base data changes.
  410. */
  411. this._renderChangesSubscription = Subscription.EMPTY;
  412. /**
  413. * Data accessor function that is used for accessing data properties for sorting through
  414. * the default sortData function.
  415. * This default function assumes that the sort header IDs (which defaults to the column name)
  416. * matches the data's properties (e.g. column Xyz represents data['Xyz']).
  417. * May be set to a custom function for different behavior.
  418. * @param data Data object that is being accessed.
  419. * @param sortHeaderId The name of the column that represents the data.
  420. */
  421. this.sortingDataAccessor = (/**
  422. * @param {?} data
  423. * @param {?} sortHeaderId
  424. * @return {?}
  425. */
  426. (data, sortHeaderId) => {
  427. /** @type {?} */
  428. const value = ((/** @type {?} */ (data)))[sortHeaderId];
  429. if (_isNumberValue(value)) {
  430. /** @type {?} */
  431. const numberValue = Number(value);
  432. // Numbers beyond `MAX_SAFE_INTEGER` can't be compared reliably so we
  433. // leave them as strings. For more info: https://goo.gl/y5vbSg
  434. return numberValue < MAX_SAFE_INTEGER ? numberValue : value;
  435. }
  436. return value;
  437. });
  438. /**
  439. * Gets a sorted copy of the data array based on the state of the MatSort. Called
  440. * after changes are made to the filtered data or when sort changes are emitted from MatSort.
  441. * By default, the function retrieves the active sort and its direction and compares data
  442. * by retrieving data using the sortingDataAccessor. May be overridden for a custom implementation
  443. * of data ordering.
  444. * @param data The array of data that should be sorted.
  445. * @param sort The connected MatSort that holds the current sort state.
  446. */
  447. this.sortData = (/**
  448. * @param {?} data
  449. * @param {?} sort
  450. * @return {?}
  451. */
  452. (data, sort) => {
  453. /** @type {?} */
  454. const active = sort.active;
  455. /** @type {?} */
  456. const direction = sort.direction;
  457. if (!active || direction == '') {
  458. return data;
  459. }
  460. return data.sort((/**
  461. * @param {?} a
  462. * @param {?} b
  463. * @return {?}
  464. */
  465. (a, b) => {
  466. /** @type {?} */
  467. let valueA = this.sortingDataAccessor(a, active);
  468. /** @type {?} */
  469. let valueB = this.sortingDataAccessor(b, active);
  470. // If both valueA and valueB exist (truthy), then compare the two. Otherwise, check if
  471. // one value exists while the other doesn't. In this case, existing value should come first.
  472. // This avoids inconsistent results when comparing values to undefined/null.
  473. // If neither value exists, return 0 (equal).
  474. /** @type {?} */
  475. let comparatorResult = 0;
  476. if (valueA != null && valueB != null) {
  477. // Check if one value is greater than the other; if equal, comparatorResult should remain 0.
  478. if (valueA > valueB) {
  479. comparatorResult = 1;
  480. }
  481. else if (valueA < valueB) {
  482. comparatorResult = -1;
  483. }
  484. }
  485. else if (valueA != null) {
  486. comparatorResult = 1;
  487. }
  488. else if (valueB != null) {
  489. comparatorResult = -1;
  490. }
  491. return comparatorResult * (direction == 'asc' ? 1 : -1);
  492. }));
  493. });
  494. /**
  495. * Checks if a data object matches the data source's filter string. By default, each data object
  496. * is converted to a string of its properties and returns true if the filter has
  497. * at least one occurrence in that string. By default, the filter string has its whitespace
  498. * trimmed and the match is case-insensitive. May be overridden for a custom implementation of
  499. * filter matching.
  500. * @param data Data object used to check against the filter.
  501. * @param filter Filter string that has been set on the data source.
  502. * @return Whether the filter matches against the data
  503. */
  504. this.filterPredicate = (/**
  505. * @param {?} data
  506. * @param {?} filter
  507. * @return {?}
  508. */
  509. (data, filter) => {
  510. // Transform the data into a lowercase string of all property values.
  511. /** @type {?} */
  512. const dataStr = Object.keys(data).reduce((/**
  513. * @param {?} currentTerm
  514. * @param {?} key
  515. * @return {?}
  516. */
  517. (currentTerm, key) => {
  518. // Use an obscure Unicode character to delimit the words in the concatenated string.
  519. // This avoids matches where the values of two columns combined will match the user's query
  520. // (e.g. `Flute` and `Stop` will match `Test`). The character is intended to be something
  521. // that has a very low chance of being typed in by somebody in a text field. This one in
  522. // particular is "White up-pointing triangle with dot" from
  523. // https://en.wikipedia.org/wiki/List_of_Unicode_characters
  524. return currentTerm + ((/** @type {?} */ (data)))[key] + '◬';
  525. }), '').toLowerCase();
  526. // Transform the filter by converting it to lowercase and removing whitespace.
  527. /** @type {?} */
  528. const transformedFilter = filter.trim().toLowerCase();
  529. return dataStr.indexOf(transformedFilter) != -1;
  530. });
  531. this._data = new BehaviorSubject(initialData);
  532. this._updateChangeSubscription();
  533. }
  534. /**
  535. * Array of data that should be rendered by the table, where each object represents one row.
  536. * @return {?}
  537. */
  538. get data() { return this._data.value; }
  539. /**
  540. * @param {?} data
  541. * @return {?}
  542. */
  543. set data(data) { this._data.next(data); }
  544. /**
  545. * Filter term that should be used to filter out objects from the data array. To override how
  546. * data objects match to this filter string, provide a custom function for filterPredicate.
  547. * @return {?}
  548. */
  549. get filter() { return this._filter.value; }
  550. /**
  551. * @param {?} filter
  552. * @return {?}
  553. */
  554. set filter(filter) { this._filter.next(filter); }
  555. /**
  556. * Instance of the MatSort directive used by the table to control its sorting. Sort changes
  557. * emitted by the MatSort will trigger an update to the table's rendered data.
  558. * @return {?}
  559. */
  560. get sort() { return this._sort; }
  561. /**
  562. * @param {?} sort
  563. * @return {?}
  564. */
  565. set sort(sort) {
  566. this._sort = sort;
  567. this._updateChangeSubscription();
  568. }
  569. /**
  570. * Instance of the MatPaginator component used by the table to control what page of the data is
  571. * displayed. Page changes emitted by the MatPaginator will trigger an update to the
  572. * table's rendered data.
  573. *
  574. * Note that the data source uses the paginator's properties to calculate which page of data
  575. * should be displayed. If the paginator receives its properties as template inputs,
  576. * e.g. `[pageLength]=100` or `[pageIndex]=1`, then be sure that the paginator's view has been
  577. * initialized before assigning it to this data source.
  578. * @return {?}
  579. */
  580. get paginator() { return this._paginator; }
  581. /**
  582. * @param {?} paginator
  583. * @return {?}
  584. */
  585. set paginator(paginator) {
  586. this._paginator = paginator;
  587. this._updateChangeSubscription();
  588. }
  589. /**
  590. * Subscribe to changes that should trigger an update to the table's rendered rows. When the
  591. * changes occur, process the current state of the filter, sort, and pagination along with
  592. * the provided base data and send it to the table for rendering.
  593. * @return {?}
  594. */
  595. _updateChangeSubscription() {
  596. // Sorting and/or pagination should be watched if MatSort and/or MatPaginator are provided.
  597. // The events should emit whenever the component emits a change or initializes, or if no
  598. // component is provided, a stream with just a null event should be provided.
  599. // The `sortChange` and `pageChange` acts as a signal to the combineLatests below so that the
  600. // pipeline can progress to the next step. Note that the value from these streams are not used,
  601. // they purely act as a signal to progress in the pipeline.
  602. /** @type {?} */
  603. const sortChange = this._sort ?
  604. (/** @type {?} */ (merge(this._sort.sortChange, this._sort.initialized))) :
  605. of(null);
  606. /** @type {?} */
  607. const pageChange = this._paginator ?
  608. (/** @type {?} */ (merge(this._paginator.page, this._internalPageChanges, this._paginator.initialized))) :
  609. of(null);
  610. /** @type {?} */
  611. const dataStream = this._data;
  612. // Watch for base data or filter changes to provide a filtered set of data.
  613. /** @type {?} */
  614. const filteredData = combineLatest(dataStream, this._filter)
  615. .pipe(map((/**
  616. * @param {?} __0
  617. * @return {?}
  618. */
  619. ([data]) => this._filterData(data))));
  620. // Watch for filtered data or sort changes to provide an ordered set of data.
  621. /** @type {?} */
  622. const orderedData = combineLatest(filteredData, sortChange)
  623. .pipe(map((/**
  624. * @param {?} __0
  625. * @return {?}
  626. */
  627. ([data]) => this._orderData(data))));
  628. // Watch for ordered data or page changes to provide a paged set of data.
  629. /** @type {?} */
  630. const paginatedData = combineLatest(orderedData, pageChange)
  631. .pipe(map((/**
  632. * @param {?} __0
  633. * @return {?}
  634. */
  635. ([data]) => this._pageData(data))));
  636. // Watched for paged data changes and send the result to the table to render.
  637. this._renderChangesSubscription.unsubscribe();
  638. this._renderChangesSubscription = paginatedData.subscribe((/**
  639. * @param {?} data
  640. * @return {?}
  641. */
  642. data => this._renderData.next(data)));
  643. }
  644. /**
  645. * Returns a filtered data array where each filter object contains the filter string within
  646. * the result of the filterTermAccessor function. If no filter is set, returns the data array
  647. * as provided.
  648. * @param {?} data
  649. * @return {?}
  650. */
  651. _filterData(data) {
  652. // If there is a filter string, filter out data that does not contain it.
  653. // Each data object is converted to a string using the function defined by filterTermAccessor.
  654. // May be overridden for customization.
  655. this.filteredData =
  656. !this.filter ? data : data.filter((/**
  657. * @param {?} obj
  658. * @return {?}
  659. */
  660. obj => this.filterPredicate(obj, this.filter)));
  661. if (this.paginator) {
  662. this._updatePaginator(this.filteredData.length);
  663. }
  664. return this.filteredData;
  665. }
  666. /**
  667. * Returns a sorted copy of the data if MatSort has a sort applied, otherwise just returns the
  668. * data array as provided. Uses the default data accessor for data lookup, unless a
  669. * sortDataAccessor function is defined.
  670. * @param {?} data
  671. * @return {?}
  672. */
  673. _orderData(data) {
  674. // If there is no active sort or direction, return the data without trying to sort.
  675. if (!this.sort) {
  676. return data;
  677. }
  678. return this.sortData(data.slice(), this.sort);
  679. }
  680. /**
  681. * Returns a paged slice of the provided data array according to the provided MatPaginator's page
  682. * index and length. If there is no paginator provided, returns the data array as provided.
  683. * @param {?} data
  684. * @return {?}
  685. */
  686. _pageData(data) {
  687. if (!this.paginator) {
  688. return data;
  689. }
  690. /** @type {?} */
  691. const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
  692. return data.slice(startIndex, startIndex + this.paginator.pageSize);
  693. }
  694. /**
  695. * Updates the paginator to reflect the length of the filtered data, and makes sure that the page
  696. * index does not exceed the paginator's last page. Values are changed in a resolved promise to
  697. * guard against making property changes within a round of change detection.
  698. * @param {?} filteredDataLength
  699. * @return {?}
  700. */
  701. _updatePaginator(filteredDataLength) {
  702. Promise.resolve().then((/**
  703. * @return {?}
  704. */
  705. () => {
  706. /** @type {?} */
  707. const paginator = this.paginator;
  708. if (!paginator) {
  709. return;
  710. }
  711. paginator.length = filteredDataLength;
  712. // If the page index is set beyond the page, reduce it to the last page.
  713. if (paginator.pageIndex > 0) {
  714. /** @type {?} */
  715. const lastPageIndex = Math.ceil(paginator.length / paginator.pageSize) - 1 || 0;
  716. /** @type {?} */
  717. const newPageIndex = Math.min(paginator.pageIndex, lastPageIndex);
  718. if (newPageIndex !== paginator.pageIndex) {
  719. paginator.pageIndex = newPageIndex;
  720. // Since the paginator only emits after user-generated changes,
  721. // we need our own stream so we know to should re-render the data.
  722. this._internalPageChanges.next();
  723. }
  724. }
  725. }));
  726. }
  727. /**
  728. * Used by the MatTable. Called when it connects to the data source.
  729. * \@docs-private
  730. * @return {?}
  731. */
  732. connect() { return this._renderData; }
  733. /**
  734. * Used by the MatTable. Called when it is destroyed. No-op.
  735. * \@docs-private
  736. * @return {?}
  737. */
  738. disconnect() { }
  739. }
  740. /**
  741. * @fileoverview added by tsickle
  742. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  743. */
  744. /**
  745. * @fileoverview added by tsickle
  746. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  747. */
  748. export { MatTableModule, MatCellDef, MatHeaderCellDef, MatFooterCellDef, MatColumnDef, MatHeaderCell, MatFooterCell, MatCell, MatTable, MatHeaderRowDef, MatFooterRowDef, MatRowDef, MatHeaderRow, MatFooterRow, MatRow, MatTableDataSource, MatTextColumn };
  749. //# sourceMappingURL=table.js.map