|
| 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 | + |
| 9 | +import {Directive, Inject, Injectable, Input} from '@angular/core'; |
| 10 | +import {CdkTable} from '@angular/cdk/table/table'; |
| 11 | +import {DOCUMENT} from '@angular/common'; |
| 12 | +import { |
| 13 | + _TABLE_LAYOUT_STRATEGY, |
| 14 | + _TableLayoutStrategy, |
| 15 | + _DefaultTableLayoutStrategy, |
| 16 | +} from '@angular/cdk/table/table-layout-strategy'; |
| 17 | + |
| 18 | +/** |
| 19 | + * A {@link _TableLayoutStrategy} that enables scrollable body content for flex tables. |
| 20 | + */ |
| 21 | +@Injectable() |
| 22 | +class ScrollableTableBodyLayoutStrategy implements _TableLayoutStrategy { |
| 23 | + private defaultLayout: _DefaultTableLayoutStrategy; |
| 24 | + private _pendingMaxHeight = 'none'; |
| 25 | + private _scrollViewport?: HTMLElement; |
| 26 | + readonly headerCssClass = 'cdk-table-scrollable-table-header'; |
| 27 | + readonly bodyCssClass = 'cdk-table-scrollable-table-body'; |
| 28 | + readonly footerCssClass = 'cdk-table-scrollable-table-footer'; |
| 29 | + |
| 30 | + constructor(@Inject(DOCUMENT) private readonly _document: any) { |
| 31 | + this.defaultLayout = new _DefaultTableLayoutStrategy(this._document); |
| 32 | + } |
| 33 | + |
| 34 | + /** |
| 35 | + * Returns the DOM structure for a native table. Scrollable body content is not supported for |
| 36 | + * native tables. Return `null` to use the default {@link CdkTable} native table layout. |
| 37 | + */ |
| 38 | + getNativeLayout(table: CdkTable<unknown>): DocumentFragment { |
| 39 | + return this.defaultLayout.getNativeLayout(table); |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * Returns the DOM structure for a flex table with scrollable body content. Each row outlet |
| 44 | + * (header, body, footer) is wrapped in a separate container. The specified max height is applied |
| 45 | + * to the body row outlet to make its content scrollable. |
| 46 | + */ |
| 47 | + getFlexLayout(table: CdkTable<unknown>): DocumentFragment { |
| 48 | + const documentFragment = this._document.createDocumentFragment(); |
| 49 | + const sections = [ |
| 50 | + {selector: this.headerCssClass, outlets: [table._headerRowOutlet]}, |
| 51 | + {selector: this.bodyCssClass, outlets: [table._rowOutlet, table._noDataRowOutlet]}, |
| 52 | + {selector: this.footerCssClass, outlets: [table._footerRowOutlet]}, |
| 53 | + ]; |
| 54 | + |
| 55 | + for (const section of sections) { |
| 56 | + const element = this._document.createElement('div'); |
| 57 | + element.classList.add(section.selector); |
| 58 | + for (const outlet of section.outlets) { |
| 59 | + element.appendChild(outlet.elementRef.nativeElement); |
| 60 | + } |
| 61 | + |
| 62 | + documentFragment.appendChild(element); |
| 63 | + } |
| 64 | + |
| 65 | + this._scrollViewport = documentFragment.querySelector(`.${this.bodyCssClass}`); |
| 66 | + this._scrollViewport!.style.overflow = 'auto'; |
| 67 | + this._applyMaxHeight(this._scrollViewport!, this._pendingMaxHeight); |
| 68 | + |
| 69 | + return documentFragment; |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Show a scroll bar if the table's body exceeds this height. The height may be specified with |
| 74 | + * any valid CSS unit of measurement. |
| 75 | + */ |
| 76 | + setMaxHeight(v: string) { |
| 77 | + this._pendingMaxHeight = v; |
| 78 | + if (this._scrollViewport) { |
| 79 | + this._applyMaxHeight(this._scrollViewport, v); |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + private _applyMaxHeight(el: HTMLElement, maxHeight: string) { |
| 84 | + el.style.maxHeight = maxHeight; |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +/** A directive that enables scrollable body content for flex tables. */ |
| 89 | +@Directive({ |
| 90 | + selector: 'cdk-table[scrollableBody], mat-table[scrollableBody]', |
| 91 | + providers: [ |
| 92 | + {provide: _TABLE_LAYOUT_STRATEGY, useClass: ScrollableTableBodyLayoutStrategy}, |
| 93 | + ] |
| 94 | +}) |
| 95 | +export class CdkScrollableTableBody { |
| 96 | + /** |
| 97 | + * Show a scroll bar if the table's body exceeds this height. The height may be specified with |
| 98 | + * any valid CSS unit of measurement. |
| 99 | + */ |
| 100 | + @Input('scrollableBody') |
| 101 | + get maxHeight() { |
| 102 | + return this._maxHeight; |
| 103 | + } |
| 104 | + set maxHeight(v: string) { |
| 105 | + this._maxHeight = v; |
| 106 | + this._layoutStrategy.setMaxHeight(v); |
| 107 | + } |
| 108 | + private _maxHeight = ''; |
| 109 | + |
| 110 | + constructor(@Inject(_TABLE_LAYOUT_STRATEGY) |
| 111 | + private readonly _layoutStrategy: ScrollableTableBodyLayoutStrategy) { |
| 112 | + } |
| 113 | +} |
0 commit comments