ng-devui
Version:
DevUI components based on Angular
876 lines • 215 kB
JavaScript
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { DOCUMENT } from '@angular/common';
import { ChangeDetectorRef, Component, ContentChild, ContentChildren, ElementRef, EventEmitter, forwardRef, HostBinding, Inject, Input, NgZone, Output, QueryList, Renderer2, TemplateRef, ViewChild, } from '@angular/core';
import { merge } from 'rxjs';
import { switchMap, takeUntil } from 'rxjs/operators';
import { DataTableHeadComponent } from './data-table-head.component';
import { DATA_TABLE } from './data-table.token';
import { TableTbodyComponent } from './table/body/tbody.component';
import { TableThComponent } from './table/head/th/th.component';
import { TableTheadComponent } from './table/head/thead.component';
import { DataTableColumnTmplComponent } from './tmpl/data-table-column-tmpl.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/cdk/scrolling";
import * as i3 from "ng-devui/dragdrop";
import * as i4 from "ng-devui/utils";
import * as i5 from "./data-table-body.component";
import * as i6 from "./data-table-head.component";
import * as i7 from "./table/body/tbody.component";
const SCROLL_BAR_WIDTH = 8;
export class DataTableComponent {
get hostHeight() {
return this.tableHeight && this.dataSource.length ? this.tableHeight : null;
}
get hasShadow() {
return this.shadowType === 'normal';
}
set content(content) {
setTimeout(() => {
this.tableBodyEl = content;
if (this.virtualScroll) {
this.initVirtualBodyHeight();
}
});
}
set dataSource(dataSource) {
if (dataSource === null || !dataSource) {
/* eslint-disable-next-line no-param-reassign */
dataSource = [];
}
this._dataSource = dataSource;
const hasChecked = this.dataSource.some(this.hasChecked);
const hasUnChecked = this.dataSource.some(this.hasUnChecked);
this._pageAllChecked = dataSource && dataSource.length > 0 && !hasUnChecked;
this.halfChecked = hasChecked && hasUnChecked;
if (this.innerHeader) {
this.innerHeader.setHeaderCheckStatus({ pageAllChecked: this._pageAllChecked, pageHalfChecked: this.halfChecked });
}
// 固定表头时,数据从无数据到有数据,需要更新滚动位置,避免对齐偏移
if (this.fixHeader) {
setTimeout(() => {
this.onBodyScroll();
});
}
if (this.virtualScroll) {
this.initVirtualBodyHeight();
}
this.initScrollStatus();
}
get dataSource() {
return this._dataSource;
}
set hideColumn(hideColumn) {
this._hideColumn = hideColumn;
if (this._columns) {
this.updateColumns();
}
}
get hideColumn() {
return this._hideColumn;
}
set pageAllChecked(pageAllChecked) {
if (this.dataSource) {
this._dataSource = this.setCheckedStatus(this.dataSource, pageAllChecked);
}
this._pageAllChecked = pageAllChecked;
this.halfChecked = this.dataSource.some(this.hasChecked) && this.dataSource.some(this.hasUnChecked);
}
get pageAllChecked() {
return this._pageAllChecked;
}
constructor(elementRef, ngZone, renderer, cdr, doc) {
this.elementRef = elementRef;
this.ngZone = ngZone;
this.renderer = renderer;
this.cdr = cdr;
this.doc = doc;
/**
* 【可选】表头checkbox是否可见
*/
this.headerCheckVisible = true;
this.checkOptionsIndex = 1050;
this.selectOptionOnCheckbox = false;
/**
* 【可选】默认表格使用的表格类型,可选值为'cell' @deprecated
*/
this.editModel = 'cell';
/**
* 鼠标悬浮行时是否高亮
*/
this.rowHoveredHighlight = true;
/**
* 表格宽度
*/
this.tableWidth = '100%';
/**
* 固定表头指定高度是否包含表头的高度,`tableHeight`设置的高度默认是表格body的高度
*/
this.containFixHeaderHeight = false;
/**
* 【可选】多列选择数组,用来指导那几列会被排序
*/
this.multiSort = [];
/**
* 【可选】用来自定义不可拖拽的前几列
*/
this.colDropFreezeTo = 0;
/**
* 【可选】同时绑定单击、双击事件时,用于区分点击的时间间隔,默认300ms,两个事件不同时使用可以指定为0
*/
this.timeout = 300;
/**
* 【可选】配置表头操作未激活状态下是否显示操作区域,默认不显示
*/
this.showOperationArea = false;
/**
* 【可选】是否显示排序未激活图标,默认显示,
*/
this.showSortIcon = true;
/**
* 【可选】是否显示筛选未激活图标,默认显示,
*/
this.showFilterIcon = true;
/**
* 多列选择Change事件,用来更新多列选择数组, column param
* */
this.multiSortChange = new EventEmitter();
/**
* 表格单元格点击事件
*/
this.cellClick = new EventEmitter();
/**
* 表格单元格双击事件
*/
this.cellDBClick = new EventEmitter();
/**
* 表格行点击事件
*/
this.rowClick = new EventEmitter();
/**
* 表格行双击事件
*/
this.rowDBClick = new EventEmitter();
/**
* 行detail toggle事件
*/
this.detialToggle = new EventEmitter();
/**
* 表格单元格开始编辑事件
*/
this.cellEditStart = new EventEmitter();
/**
* 表格单元格结束编辑事件
*/
this.cellEditEnd = new EventEmitter();
/**
* 某行的勾选状态变化事件
*/
this.rowCheckChange = new EventEmitter();
/**
* 当前页码全勾选状态变化事件
*/
this.checkAllChange = new EventEmitter();
/**
* 延迟懒加载完成事件
*/
this.loadMore = new EventEmitter();
/**
* 列宽变化事件
*/
this.resize = new EventEmitter();
/**
* 当前表格层级,默认为0,在树形表格场景下自增长
* 内部嵌套使用,不对外暴露
*/
this.tableLevel = 0;
/**
* 配置树形表格的父子选中是否互相关联
* upward:选中子关联父
* downward: 选中父关联子
*/
this.checkableRelation = { upward: true, downward: true };
/**
* 子列表关闭事件
*/
this.childrenTableClose = new EventEmitter();
/**
* 全部子列表关闭事件
*/
this.allChildrenTableClose = new EventEmitter();
/**
* 虚拟滚动配置
*/
this.virtualItemSize = 40;
this.virtualMinBufferPx = 80;
this.virtualMaxBufferPx = 200;
/**
* 列宽配置
*/
this.tableWidthConfig = [];
/**
* 表格布局
*/
this.tableLayout = 'fixed';
/**
* 表格边框类型,默认有行边框,bordered:全边框,borderless:无边框
*/
this.borderType = '';
/**
* 表格内部滚动事件
*/
this.tableScrollEvent = new EventEmitter();
this.columnDragEnd = new EventEmitter();
/**
* 表格尺寸,sm对应行高40px, md对应行高48px,lg对应行高56px
*/
this.size = 'sm';
this.shadowType = 'embed';
this.tableOverflowType = 'auto';
this._dataSource = [];
this._pageAllChecked = false;
this.selectable = true;
this.allChecked = [];
this.documentClickEvent = new EventEmitter();
this.cellEditorClickEvent = new EventEmitter();
this._hideColumn = [];
this.searchQueryChange = new EventEmitter();
this.halfChecked = false;
this.scrollY = 0;
this.BUILTIN_COL_WIDTH = '41px';
this.BUILTIN_COL_WIDTH_EXTRA = '55px';
this._tableTotalWidth = 0;
this._lastColSize = 0;
// 判断数据是否存在选中状态
this.hasChecked = (data) => {
if (data.$checked) {
return true;
}
if (data.children) {
return data.children.some(this.hasChecked);
}
};
// 判断数据是否存在未选中状态
this.hasUnChecked = (data) => {
if (!data.$checked) {
return true;
}
if (data.children) {
return data.children.some(this.hasUnChecked);
}
};
this.onDocumentClickListen = this.onDocumentClick.bind(this);
this.document = this.doc;
}
initVirtualBodyHeight() {
setTimeout(() => {
if (this.virtualScrollViewport) {
this.virtualScrollViewport.checkViewportSize();
}
});
if (this.tableHeight && this.tableHeight !== 'auto') {
this.virtualBodyHeight = this.tableHeight;
return;
}
if (!this.maxHeight) {
this.virtualBodyHeight = null;
return;
}
if (this.tableBodyEl) {
const tableHeader = this.tableBodyEl.nativeElement.querySelector('thead');
const tableHeaderHeight = tableHeader?.offsetHeight + SCROLL_BAR_WIDTH || 0;
const curTotalHeight = this.dataSource.length * this.virtualItemSize + tableHeaderHeight + SCROLL_BAR_WIDTH;
this.virtualBodyHeight = curTotalHeight < parseInt(this.maxHeight, 10) ? curTotalHeight + 'px' : this.maxHeight;
return;
}
}
getColumns() {
const cols = this.columns.filter((column) => {
return !this.hideColumn.some((field) => column.field === field);
});
cols.sort((first, second) => first.order - second.order);
return cols;
}
// life hook start
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.document.addEventListener('click', this.onDocumentClickListen);
});
}
ngOnChanges(changes) {
const { checkable, showExpandToggle, tableHeight, maxHeight, virtualScroll } = changes;
if (checkable) {
const checkColIndex = this.tableWidthConfig.findIndex((config) => {
return config.field === 'checkbox';
});
if (this.checkable) {
if (checkColIndex < 0) {
if (this.showExpandToggle) {
this.tableWidthConfig.splice(1, 0, { field: 'checkbox', width: this.BUILTIN_COL_WIDTH });
}
else {
this.tableWidthConfig.unshift({ field: 'checkbox', width: this.BUILTIN_COL_WIDTH });
}
}
}
else {
if (checkColIndex > -1) {
this.tableWidthConfig.splice(checkColIndex, 1);
}
}
}
if (showExpandToggle) {
const expandColIndex = this.tableWidthConfig.findIndex((config) => {
return config.field === 'expand';
});
if (this.showExpandToggle) {
if (expandColIndex < 0) {
this.tableWidthConfig.unshift({ field: 'expand', width: this.BUILTIN_COL_WIDTH });
}
}
else {
if (expandColIndex > -1) {
this.tableWidthConfig.splice(expandColIndex, 1);
}
}
}
if (this.virtualScroll &&
((tableHeight && !tableHeight.firstChange) || (maxHeight && !maxHeight.firstChange) || (virtualScroll && !virtualScroll.firstChange))) {
this.initVirtualBodyHeight();
}
}
onDocumentClick($event) {
this.documentClickEvent.emit($event);
}
ngAfterContentInit() {
if (this.columns.length > 0) {
this.updateColumns();
this.columns.forEach((col) => {
col.orderChange.subscribe(() => {
this.updateColumns();
});
col.widthChange.subscribe(() => {
this.updateColumns();
});
});
}
if (this.innerHeader) {
this.headerCheckStatusSubscription = this.innerHeader.headerCheckStatusEvent.subscribe((status) => {
this.onCheckAllChange(status);
});
this.headertoggleTableSubscription = this.innerHeader.headerChildrenTableToggleEvent.subscribe((status) => {
this.onToggleAllChildrenTable(status);
});
}
else {
this.columns.changes.subscribe(() => {
this.updateColumns();
});
}
setTimeout(() => {
this.initScrollStatus();
});
}
initScrollStatus() {
if (this.tableOverflowType !== 'overlay') {
return;
}
const ele = this.virtualScroll ? this.virtualScrollViewport?.elementRef?.nativeElement : this.normalScrollElement?.nativeElement;
this.hasWidthScroll = ele && ele.scrollWidth > ele.clientWidth;
this.hasHeightScroll = ele && ele.scrollHeight > ele.clientHeight;
}
ngAfterViewInit() {
this.thList.forEach((th) => {
th.tableViewRefElement = this.tableViewRefElement;
});
this.thList.changes.subscribe((list) => {
list.forEach((th) => {
th.tableViewRefElement = this.tableViewRefElement;
});
});
if (this.onlyOneColumnSort) {
this.resetThSortOrder();
}
setTimeout(() => {
this.initScrollClass();
});
}
// 初始化时判断是否存在横向滚动,并加上相应类名
initScrollClass() {
const ele = this.normalScrollElement?.nativeElement || this.vitualScrollElement?.elementRef?.nativeElement;
if (ele.clientWidth !== ele.scrollWidth) {
this.setScrollViewClass('left');
}
}
resetThSortOrder() {
merge(...this.thList?.map((th) => th.sortChange))
.pipe(takeUntil(this.thList.changes))
.subscribe((sortEvent) => {
this.thList.filter((th) => th !== sortEvent.th).forEach((th) => th.clearSortOrder());
});
this.thList.changes.pipe(switchMap(() => merge(...this.thList.map((th) => th.sortChange)))).subscribe((sortEvent) => {
this.thList.filter((th) => th !== sortEvent.th).forEach((th) => th.clearSortOrder());
});
}
updateColumns() {
this._columns = this.getColumns();
this.tableWidthConfig = [];
if (this.showExpandToggle) {
this.tableWidthConfig.push({ field: 'expand', width: this.BUILTIN_COL_WIDTH });
}
if (this.checkable) {
if (this.checkOptions && this.checkOptions.length > 0) {
this.tableWidthConfig.push({ field: 'checkbox', width: this.BUILTIN_COL_WIDTH_EXTRA });
}
else {
this.tableWidthConfig.push({ field: 'checkbox', width: this.BUILTIN_COL_WIDTH });
}
}
this._columns.forEach((col) => {
this.tableWidthConfig.push({ field: col.field, width: col.width });
});
}
ngOnDestroy() {
this.unSubscription();
this.document.removeEventListener('click', this.onDocumentClickListen);
}
onHandleSort(column) {
if (this.multiSort && this.multiSort.length > 0) {
const multiSortIndex = this.multiSort.findIndex((item) => item.field === column.field);
if (multiSortIndex !== -1) {
this.multiSort.splice(multiSortIndex, 1);
}
if (column.direction === '') {
this.multiSortChange.emit(this.multiSort);
return;
}
if (!this.onlyOneColumnSort) {
this.multiSort.push(column);
}
else {
this.multiSort = [column];
}
}
else {
this.multiSort = [column];
}
this.multiSortChange.emit(this.multiSort);
}
onCellClick($event) {
this.selectedRowItem = $event.rowItem;
this.selectedColumnItem = $event.column;
this.ngZone.run(() => {
this.cellClick.emit($event);
});
}
onCellEditStart($event) {
this.isCellEdit = true;
this.cellEditStart.emit($event);
}
onCellEditEnd($event) {
this.isCellEdit = false;
this.cellEditEnd.emit($event);
}
onCellDBClick($event) {
this.ngZone.run(() => {
this.cellDBClick.emit($event);
});
}
onRowClick($event) {
this.selectedRowItem = $event.rowItem;
this.ngZone.run(() => {
this.rowClick.emit($event);
});
}
onRowDBClick($event) {
this.ngZone.run(() => {
this.rowDBClick.emit($event);
});
}
onDetailToggle($event) {
this.detialToggle.emit($event);
}
setRowCheckStatus($event) {
// 处理children的选中
if ($event.rowItem.children && this.checkableRelation.downward) {
this.setCheckedStatus($event.rowItem.children, $event.checked);
}
// 处理parents的选中
if (this.checkableRelation.upward) {
const nestedIndexArray = $event.nestedIndex.split(',');
nestedIndexArray.shift();
const nestedIndexArrayToInt = nestedIndexArray.map((value) => {
return parseInt(value, 10);
});
// 通过选中行的父级索引设置父的选中状态
this.setParentCheckStatus(nestedIndexArrayToInt);
}
// 处理整个table header的选中
const hasChecked = this.dataSource.some(this.hasChecked);
if ($event) {
const hasUnChecked = this.dataSource.some(this.hasUnChecked);
this._pageAllChecked = !hasUnChecked;
this.halfChecked = hasChecked && hasUnChecked;
}
else {
this._pageAllChecked = false;
this.halfChecked = hasChecked;
}
if (this.innerHeader) {
this.innerHeader.setHeaderCheckStatus({ pageAllChecked: this._pageAllChecked, pageHalfChecked: this.halfChecked });
}
this.rowCheckChange.emit($event);
}
setParentCheckStatus(nestedIndex) {
if (nestedIndex.length > 0) {
const topIndex = nestedIndex[0];
const topParent = this.dataSource[topIndex];
const argNestedIndex = [...nestedIndex];
argNestedIndex.shift();
const lastParent = this.findLastParent(topParent, argNestedIndex);
this.setSelfCheckStatus(lastParent);
nestedIndex.pop();
if (nestedIndex.length > 0) {
this.setParentCheckStatus(nestedIndex);
}
}
}
findLastParent(source, indexArray) {
if (source && indexArray.length > 0) {
const topIndex = indexArray[0];
const topParent = source.children[topIndex];
indexArray.shift();
return this.findLastParent(topParent, indexArray);
}
else {
return source;
}
}
setSelfCheckStatus(data) {
if (data && data.children) {
const hasUnChecked = data.children.some((child) => {
return !child.$checked;
});
const hasChecked = data.children.some((child) => {
return child.$checked || child.$halfChecked;
});
data.$checked = !hasUnChecked;
data.$halfChecked = hasUnChecked && hasChecked;
}
}
setCheckedStatus(data, checked, toggle) {
return data.map((item) => {
if (!(item.$checkDisabled || item.$disabled)) {
if ((toggle && item.$checked === undefined) || !toggle) {
item.$checked = checked;
item.$halfChecked = false;
}
}
if (item.children) {
item.children = this.setCheckedStatus(item.children, checked, toggle);
}
return item;
});
}
onCheckAllChange($event) {
this.pageAllChecked = $event;
this.checkAllChange.emit($event);
}
onSearchQueryChange($event) {
this.searchQueryChange.emit($event);
}
getSelectedRowItem() {
return this.selectedRowItem;
}
onLoadMore(event) {
this.loadMore.emit(this);
}
updateColumnsWidth() {
this.tableWidthConfig = [];
if (this.showExpandToggle) {
const expandWidth = this.elementRef.nativeElement.querySelector('.devui-detail-cell').clientWidth;
this.tableWidthConfig.push({ field: 'expand', width: expandWidth + 'px' });
}
if (this.checkable) {
const list = this.elementRef.nativeElement.querySelectorAll('.devui-checkable-cell');
const checkboxWidth = list[list.length - 1].clientWidth;
this.tableWidthConfig.push({ field: 'checkbox', width: checkboxWidth + 'px' });
}
this._columns.forEach((col) => {
this.tableWidthConfig.push({ field: col.field, width: col.width });
});
}
beginResizeHandlerEvent($event) {
const thRenderWidthList = $event.thRenderWidthList;
if (thRenderWidthList.length > 0) {
this._tableTotalWidth = this.elementRef.nativeElement.querySelector('.table-wrap').offsetWidth - 8;
// 兼容d-column表头分组场景
const reverseThList = thRenderWidthList.reverse();
this._columns.forEach((column) => {
const thItem = reverseThList.find((th) => th.field === column.field);
if (thItem) {
column.width = thItem.width + 'px';
}
});
if (!this._lastColSize) {
this._lastColSize = parseInt(this._columns.slice(-1)[0].width, 10);
}
this.updateColumnsWidth();
}
this.onDocumentClick($event.event);
}
onResizingFixedHandler({ field, width }) {
if (this.resizeable) {
const index = this.tableWidthConfig.findIndex((config) => {
return config.field === field;
});
if (index > -1) {
setTimeout(() => {
this.tableWidthConfig[index].width = width + 'px';
});
}
}
}
onResizeHandler({ width, field }) {
if (width < 0) {
return;
}
const index = this.tableWidthConfig.findIndex((config) => {
return config.field === field;
});
if (index > -1) {
this.tableWidthConfig[index].width = width + 'px';
}
const curTotal = this.tableWidthConfig.reduce((pre, cur) => {
const value = pre + parseInt(cur.width, 10);
return value;
}, 0);
let columnResizeEventArg;
this._columns = this._columns.map((column, colIndex) => {
if (column.field === field) {
column.width = parseInt(width, 10) + 'px';
columnResizeEventArg = { currentColumn: column, nextColumn: this._columns[colIndex + 1] };
this.resize.emit(columnResizeEventArg);
}
return column;
});
const changeSize = curTotal - this._tableTotalWidth;
const lastCol = this._columns.slice(-1)[0];
const lastColWidth = parseInt(lastCol.width, 10);
if (changeSize < 0 && columnResizeEventArg.nextColumn) {
const newSize = parseInt(lastCol.width) - changeSize + 'px';
lastCol.width = newSize;
this.tableWidthConfig[this.tableWidthConfig.length - 1].width = newSize;
}
else if (this._lastColSize < lastColWidth) {
const lastChange = lastColWidth - this._lastColSize > changeSize ? changeSize : lastColWidth - this._lastColSize;
lastCol.width = lastColWidth - lastChange + 'px';
this.tableWidthConfig[this.tableWidthConfig.length - 1].width = lastColWidth - lastChange + 'px';
}
}
handleDragTable({ from, to }) {
this.columnDragEnd.emit({ from, to });
const sortArray = (array, fromE, toE) => {
if (fromE < toE) {
const fromEData = array[fromE];
for (let i = 0; i < array.length; i++) {
if (i >= fromE && i < toE) {
this.ngZone.run(() => {
array[i] = array[i + 1];
});
}
}
this.ngZone.run(() => {
array[toE] = fromEData;
});
}
if (fromE > toE) {
const fromEData = array[fromE];
for (let i = array.length; i > 0; i--) {
if (i <= fromE && i > toE) {
array[i] = array[i - 1];
}
}
array[toE] = fromEData;
}
};
sortArray(this._columns, from, to);
this._columns.forEach((item, index) => {
item.order = index;
});
}
onBodyScroll(event) {
const target = event?.target
|| this.normalScrollElement?.nativeElement
|| this.virtualScrollViewport?.elementRef.nativeElement;
if (this.isCellEdit) {
// Y轴滚动距离超过tr高度时取消目前编辑状态
if (this.scrollY === 0) {
this.scrollY = target.scrollTop;
}
const offset = target.scrollTop - this.scrollY;
if (offset > 40 || offset < -40) {
this.cancelEditingStatus();
this.scrollY = 0;
}
}
const scrollLeft = target.scrollLeft;
if (scrollLeft === 0) {
if (target.clientWidth === target.scrollWidth) {
this.setScrollViewClass('none');
}
else {
this.setScrollViewClass('left');
}
}
else if (Math.abs(scrollLeft + target.clientWidth - target.scrollWidth) < 1) {
this.setScrollViewClass('right');
}
else {
this.setScrollViewClass('middle');
}
if (this.fixHeader) {
this.fixHeaderContainerRefElement.nativeElement.scrollLeft = scrollLeft;
}
this.tableScrollEvent.emit(event);
}
setScrollViewClass(position) {
const element = this.tableViewRefElement.nativeElement;
const className = 'devui-table-scroll-' + position;
const elClassList = element.classList;
if (!elClassList.contains(className)) {
for (let index = 0; index < elClassList.length; index++) {
const clName = elClassList[index];
if (clName.startsWith('devui-table-scroll-')) {
this.renderer.removeClass(element, clName);
}
}
this.renderer.addClass(element, className);
}
}
unSubscription() {
if (this.headerCheckStatusSubscription) {
this.headerCheckStatusSubscription.unsubscribe();
this.headerCheckStatusSubscription = null;
}
if (this.headertoggleTableSubscription) {
this.headertoggleTableSubscription.unsubscribe();
this.headertoggleTableSubscription = null;
}
}
setRowChildToggleStatus(rowItem, open) {
if (open) {
let loadChildrenResult = Promise.resolve(true);
if (this.loadChildrenTable) {
loadChildrenResult = this.loadChildrenTable(rowItem);
}
loadChildrenResult.then(() => {
// 异步加载子表格是检查选中状态
if (rowItem.$checked && this.checkableRelation.downward) {
this.setCheckedStatus(rowItem.children, rowItem.$checked, true);
}
});
}
else {
this.childrenTableClose.emit(rowItem);
}
}
setTableChildrenToggleStatus(open) {
this.onToggleAllChildrenTable(open);
if (this.innerHeader) {
this.innerHeader.setHeaderToggleStatus(open);
}
else {
this.childrenTableOpen = open;
}
}
travelChildrenToggleStatus(data, open) {
return data.map((item) => {
if (item.children) {
item.$isChildTableOpen = open;
item.children = this.travelChildrenToggleStatus(item.children, open);
}
return item;
});
}
// 切换表头的子表格展开收起
onToggleAllChildrenTable(open) {
this.childrenTableOpen = open;
if (open) {
let loadAllChildrenResult = Promise.resolve(true);
if (this.loadAllChildrenTable) {
loadAllChildrenResult = this.loadAllChildrenTable();
}
loadAllChildrenResult.then(() => {
this.dataSource.forEach((item) => {
if (item.$checked && item.children) {
this.setCheckedStatus(item.children, true, true);
}
});
this.travelChildrenToggleStatus(this.dataSource, open);
});
}
else {
this.travelChildrenToggleStatus(this.dataSource, open);
this.allChildrenTableClose.emit();
}
}
cancelEditingStatus() {
this.documentClickEvent.emit('cancel');
}
collectCheckedRows(dist, source) {
source.forEach((row) => {
if (row.$checked) {
dist.push(row);
}
if (row.children) {
this.collectCheckedRows(dist, row.children);
}
});
}
getCheckedRows() {
if (this.checkableRelation.upward) {
// 如果children的选中状态关联parent的选中状态,只需返回最外层的数据
return this.dataSource ? this.dataSource.filter((item) => item.$checked || item.$halfChecked) : [];
}
else {
// 如果children的选中状态不关联parent的选中状态,遍历dataSource,将所有的选中行平级返回
const checkedRows = [];
this.collectCheckedRows(checkedRows, this.dataSource);
return checkedRows;
}
}
setTableCheckStatus(status) {
if (status.pageAllChecked !== undefined) {
// 设置全选
if (this.dataSource) {
this._dataSource = this.setCheckedStatus(this.dataSource, status.pageAllChecked);
}
this._pageAllChecked = status.pageAllChecked;
if (status.pageAllChecked) {
// 全选为true
this.halfChecked = false;
}
else {
this.halfChecked = this.dataSource.some(this.hasChecked) && this.dataSource.some(this.hasUnChecked);
}
}
if (status.pageHalfChecked !== undefined) {
// 设置半选
this.halfChecked = status.pageHalfChecked;
}
if (this.innerHeader) {
this.innerHeader.setHeaderCheckStatus({ pageAllChecked: this._pageAllChecked, pageHalfChecked: this.halfChecked });
}
}
// 更新cdk虚拟滚动viewport size并重新渲染,解决父层高度变化渲染数据size没有更新问题
updateVirtualScrollSize() {
this.virtualScrollViewport.checkViewportSize();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DataTableComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DataTableComponent, selector: "d-data-table", inputs: { checkable: "checkable", headerCheckDisabled: "headerCheckDisabled", headerCheckVisible: "headerCheckVisible", checkOptions: "checkOptions", checkOptionsIndex: "checkOptionsIndex", selectOptionOnCheckbox: "selectOptionOnCheckbox", showExpandToggle: "showExpandToggle", fixHeader: "fixHeader", scrollable: "scrollable", editModel: "editModel", maxWidth: "maxWidth", maxHeight: "maxHeight", type: "type", rowHoveredHighlight: "rowHoveredHighlight", generalRowHoveredData: "generalRowHoveredData", cssClass: "cssClass", tableWidth: "tableWidth", tableHeight: "tableHeight", containFixHeaderHeight: "containFixHeaderHeight", onlyOneColumnSort: "onlyOneColumnSort", multiSort: "multiSort", resizeable: "resizeable", colDraggable: "colDraggable", colDropFreezeTo: "colDropFreezeTo", detailTemplateRef: "detailTemplateRef", timeout: "timeout", showOperationArea: "showOperationArea", showSortIcon: "showSortIcon", showFilterIcon: "showFilterIcon", beforeCellEdit: "beforeCellEdit", beforeCellEditEnd: "beforeCellEditEnd", tableLevel: "tableLevel", checkableRelation: "checkableRelation", loadChildrenTable: "loadChildrenTable", loadAllChildrenTable: "loadAllChildrenTable", virtualScroll: "virtualScroll", headerExpandConfig: "headerExpandConfig", virtualItemSize: "virtualItemSize", virtualMinBufferPx: "virtualMinBufferPx", virtualMaxBufferPx: "virtualMaxBufferPx", lazy: "lazy", tableWidthConfig: "tableWidthConfig", headerBg: "headerBg", tableLayout: "tableLayout", borderType: "borderType", striped: "striped", minHeight: "minHeight", size: "size", shadowType: "shadowType", tableOverflowType: "tableOverflowType", dataSource: "dataSource", hideColumn: "hideColumn", pageAllChecked: "pageAllChecked" }, outputs: { multiSortChange: "multiSortChange", cellClick: "cellClick", cellDBClick: "cellDBClick", rowClick: "rowClick", rowDBClick: "rowDBClick", detialToggle: "detialToggle", cellEditStart: "cellEditStart", cellEditEnd: "cellEditEnd", rowCheckChange: "rowCheckChange", checkAllChange: "checkAllChange", loadMore: "loadMore", resize: "resize", childrenTableClose: "childrenTableClose", allChildrenTableClose: "allChildrenTableClose", tableScrollEvent: "tableScrollEvent", columnDragEnd: "columnDragEnd" }, host: { properties: { "style.height": "this.hostHeight", "class.devui-table-shadow": "this.hasShadow" } }, providers: [
{
provide: DATA_TABLE,
useExisting: forwardRef(() => DataTableComponent),
},
], queries: [{ propertyName: "innerHeader", first: true, predicate: TableTheadComponent, descendants: true }, { propertyName: "innerBody", first: true, predicate: TableTbodyComponent, descendants: true }, { propertyName: "noResultTemplate", first: true, predicate: ["noResultTemplateRef"], descendants: true }, { propertyName: "columns", predicate: DataTableColumnTmplComponent }, { propertyName: "thList", predicate: TableThComponent, descendants: true }], viewQueries: [{ propertyName: "fixHeaderContainerRefElement", first: true, predicate: ["fixHeaderContainerRef"], descendants: true }, { propertyName: "tableViewRefElement", first: true, predicate: ["tableView"], descendants: true, static: true }, { propertyName: "virtualScrollViewport", first: true, predicate: ["cdkVirtualScrollViewport"], descendants: true }, { propertyName: "normalScrollElement", first: true, predicate: ["normalScroll"], descendants: true }, { propertyName: "vitualScrollElement", first: true, predicate: ["scrollViewTpl"], descendants: true }, { propertyName: "columnHeaderComponent", first: true, predicate: DataTableHeadComponent, descendants: true }, { propertyName: "devuiNormalScrollBody", first: true, predicate: ["devuiNormalScrollBody"], descendants: true, read: ElementRef }, { propertyName: "content", first: true, predicate: ["tableBody"], descendants: true }], exportAs: ["dataTable"], usesOnChanges: true, ngImport: i0, template: "<div class=\"devui-data-table {{ cssClass }}\">\r\n <div\r\n class=\"devui-table-view {{ containFixHeaderHeight ? 'contain-fix-height' : '' }}\"\r\n [ngClass]=\"{\r\n 'has-width-scroll': hasWidthScroll,\r\n 'has-height-scroll': hasHeightScroll\r\n }\"\r\n #tableView\r\n >\r\n <div\r\n *ngIf=\"fixHeader\"\r\n #fixHeaderContainerRef\r\n class=\"table-wrap devui-fix-header\"\r\n [ngClass]=\"{\r\n 'shadow-fix-header': headerBg\r\n }\"\r\n [style.overflow-x]=\"dataSource?.length ? 'hidden' : 'auto'\"\r\n [style.overflow-y]=\"dataSource?.length ? 'scroll' : 'hidden'\"\r\n [style.max-height]=\"maxHeight ? maxHeight : null\"\r\n [style.max-width]=\"maxWidth ? maxWidth : null\"\r\n [style.width]=\"!maxWidth ? tableWidth : null\"\r\n >\r\n <table\r\n class=\"devui-table devui-table-{{ size }} {{ borderType ? 'table-' + borderType : '' }} {{ fixHeader ? 'table-fix-header' : '' }} {{\r\n headerBg ? 'header-bg' : ''\r\n }} {{ striped ? 'table-striped' : '' }}\"\r\n [ngClass]=\"{ 'area-active': showOperationArea }\"\r\n [style.table-layout]=\"tableLayout\"\r\n >\r\n <colgroup>\r\n <col *ngFor=\"let config of tableWidthConfig\" [style.width]=\"config.width\" />\r\n </colgroup>\r\n <ng-container *ngTemplateOutlet=\"HeaderContent\"></ng-container>\r\n <ng-template *ngIf=\"!innerHeader\" [ngTemplateOutlet]=\"headerTpl\"></ng-template>\r\n </table>\r\n </div>\r\n\r\n <div\r\n #normalScroll\r\n cdkScrollable\r\n dLazyLoad\r\n [enableLazyLoad]=\"lazy\"\r\n (loadMore)=\"onLoadMore($event)\"\r\n *ngIf=\"!virtualScroll; else scrollViewTpl\"\r\n class=\"devui-scrollbar\"\r\n [style.overflow-x]=\"dataSource?.length || !fixHeader ? 'auto' : 'hidden'\"\r\n [ngClass]=\"{\r\n 'scroll-view': scrollable,\r\n 'overflow-overlay': tableOverflowType === 'overlay',\r\n 'table-wrap': !fixHeader\r\n }\"\r\n [style.height]=\"tableHeight ? tableHeight : null\"\r\n [style.max-height]=\"maxHeight ? maxHeight : null\"\r\n [style.max-width]=\"maxWidth ? maxWidth : null\"\r\n [style.width]=\"!maxWidth ? tableWidth : null\"\r\n (scroll)=\"onBodyScroll($event)\"\r\n >\r\n <table\r\n #tableBody\r\n class=\"devui-table devui-table-{{ size }} {{ borderType ? 'table-' + borderType : '' }} {{\r\n rowHoveredHighlight ? 'table-hover' : ''\r\n }} {{ headerBg ? 'header-bg' : '' }} {{ striped ? 'table-striped' : '' }}\"\r\n [ngClass]=\"{ 'area-active': showOperationArea }\"\r\n [style.table-layout]=\"tableLayout\"\r\n [style.height]=\"minHeight ? minHeight : null\"\r\n [style.position]=\"tableOverflowType === 'overlay' ? null : 'relative'\"\r\n >\r\n <colgroup>\r\n <col *ngFor=\"let config of tableWidthConfig\" [style.width]=\"config.width\" />\r\n </colgroup>\r\n <ng-container *ngIf=\"!fixHeader\">\r\n <ng-container *ngTemplateOutlet=\"HeaderContent\"></ng-container>\r\n <ng-template *ngIf=\"!innerHeader\" [ngTemplateOutlet]=\"headerTpl\"></ng-template>\r\n </ng-container>\r\n <tbody\r\n dTableBody\r\n dSortable\r\n *ngIf=\"innerBody\"\r\n [dataSource]=\"dataSource\"\r\n [tableWidthConfig]=\"tableWidthConfig\"\r\n [rowTemplete]=\"innerBody.rowTempleteForSelect\"\r\n [minHeight]=\"minHeight\"\r\n [minHeightStretchRow]=\"innerBody.minHeightStretchRow\"\r\n ></tbody>\r\n <tbody\r\n *ngIf=\"!innerBody\"\r\n dDataTableBody\r\n #devuiNormalScrollBody\r\n [dataSource]=\"dataSource\"\r\n [resizeable]=\"resizeable\"\r\n [columns]=\"_columns\"\r\n [checkable]=\"checkable\"\r\n [allChecked]=\"_pageAllChecked\"\r\n [selectable]=\"selectable\"\r\n [editModel]=\"editModel\"\r\n [editRowItem]=\"editRowItem\"\r\n [showExpandToggle]=\"showExpandToggle\"\r\n [detailTemplateRef]=\"detailTemplateRef\"\r\n [timeout]=\"timeout\"\r\n [type]=\"type\"\r\n [rowHoveredHighlight]=\"rowHoveredHighlight\"\r\n [tableLevel]=\"tableLevel\"\r\n [tableWidthConfig]=\"tableWidthConfig\"\r\n [headerExpandConfig]=\"headerExpandConfig\"\r\n [generalRowHoveredData]=\"generalRowHoveredData\"\r\n ></tbody>\r\n </table>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div\r\n class=\"devui-no-result-wrapper\"\r\n [ngClass]=\"{ 'overlay-table-no-result': tableOverflowType === 'overlay' || !scrollable }\"\r\n *ngIf=\"!dataSource?.length && noResultTemplate != null\"\r\n>\r\n <ng-template [ngTemplateOutlet]=\"noResultTemplate\" [ngTemplateOutletContext]=\"{ $implicit: this }\"></ng-template>\r\n</div>\r\n\r\n<ng-template #scrollViewTpl>\r\n <cdk-virtual-scroll-viewport\r\n #cdkVirtualScrollViewport\r\n dLazyLoad\r\n [enableLazyLoad]=\"lazy\"\r\n (loadMore)=\"onLoadMore($event)\"\r\n [itemSize]=\"virtualItemSize\"\r\n [minBufferPx]=\"virtualMinBufferPx\"\r\n [maxBufferPx]=\"virtualMaxBufferPx\"\r\n class=\"devui-scrollbar viewport-wrapper\"\r\n [ngClass]=\"{\r\n 'scroll-view': scrollable,\r\n 'overflow-overlay': tableOverflowType === 'overlay',\r\n 'virtual-scroll-wrap': !fixHeader\r\n }\"\r\n [style.height]=\"virtualBodyHeight\"\r\n [style.max-height]=\"maxHeight ? maxHeight : null\"\r\n [style.max-width]=\"maxWidth ? maxWidth : null\"\r\n [style.width]=\"!maxWidth ? tableWidth : null\"\r\n (scroll)=\"onBodyScroll($event)\"\r\n >\r\n <table\r\n #tableBody\r\n class=\"devui-table devui-table-{{ size }} {{ borderType ? 'table-' + borderType : '' }} {{\r\n rowHoveredHighlight ? 'table-hover' : ''\r\n }} {{ headerBg ? 'header-bg' : '' }} {{ striped ? 'table-striped' : '' }}\"\r\n [ngClass]=\"{ 'area-active': showOperationArea }\"\r\n [style.table-layout]=\"tableLayout\"\r\n [style.height]=\"minHeight ? minHeight : null\"\r\n >\r\n <colgroup>\r\n <col *ngFor=\"let config of tableWidthConfig\" [style.width]=\"config.width\" />\r\n </colgroup>\r\n <ng-container *ngIf=\"!fixHeader\">\r\n <ng-container *ngTemplateOutlet=\"HeaderContent\"></ng-container>\r\n <ng-template *ngIf=\"!innerHeader\" [ngTemplateOutlet]=\"headerTpl\"></ng-template>\r\n </ng-container>\r\n <tbody\r\n dTableBody\r\n dSortable\r\n *ngIf=\"innerBody\"\r\n [dataSource]=\"dataSource\"\r\n [tableWidthConfig]=\"tableWidthConfig\"\r\n [virtualScroll]=\"virtualScroll\"\r\n [rowTemplete]=\"innerBody.rowTempleteForSelect\"\r\n [minHeight]=\"minHeight\"\r\n [minHeightStretchRow]=\"innerBody.minHeightStretchRow\"\r\n ></tbody>\r\n <tbody\r\n *ngIf=\"!innerBody\"\r\n dDataTableBody\r\n [dataSource]=\"dataSource\"\r\n [resizeable]=\"resizeable\"\r\n [columns]=\"_columns\"\r\n [checkable]=\"checkable\"\r\n [allChecked]=\"_pageAllChecked\"\r\n [selectable]=\"selectable\"\r\n [editModel]=\"editModel\"\r\n [editRowItem]=\"editRowItem\"\r\n [showExpandToggle]=\"showExpandToggle\"\r\n [detailTemplateRef]=\"detailTemplateRef\"\r\n [timeout]=\"timeout\"\r\n [type]=\"type\"\r\n [rowHoveredHighlight]=\"rowHoveredHighlight\"\r\n [tableLevel]=\"tableLevel\"\r\n [virtualScroll]=\"virtualScroll\"\r\n [tableWidthConfig]=\"tableWidthConfig\"\r\n [headerExpandConfig]=\"headerExpandConfig\"\r\n [generalRowHoveredData]=\"generalRowHoveredData\"\r\n ></tbody>\r\n </table>\r\n </cdk-virtual-scroll-viewport>\r\n</ng-template>\r\n\r\n<ng-template #headerTpl>\r\n <thead\r\n dDataTableHead\r\n [resizeable]=\"resizeable\"\r\n [checkOptionsIndex]=\"checkOptionsIndex\"\r\n [tableViewRefElement]=\"tableViewRefElement\"\r\n [tableBodyEl]=\"tableBodyEl\"\r\n [multiSort]=\"multiSort\"\r\n [columns]=\"_columns\"\r\n [pageAllChecked]=\"_pageAllChecked\"\r\n [checkable]=\"checkable\"\r\n [checkOptions]=\"checkOptions\"\r\n [selectOptionOnCheckbox]=\"selectOptionOnCheckbox\"\r\n [headerCheckDisabled]=\"headerCheckDisabled\"\r\n [headerCheckVisible]=\"headerCheckVisible\"\r\n [showExpandToggle]=\"showExpandToggle\"\r\n [showSortIcon]=\"showSortIcon\"\r\n [showFilterIcon]=\"showFilterIcon\"\r\n (resizeHandlerEvent)=\"onResizeHandler($event)\"\r\n (headClickSortEvent)=\"onHandleSort($event)\"\r\n [halfChecked]=\"halfChecked\"\r\n [maxHeight]=\"maxHeight\"\r\n (beginResizeHandlerEvent)=\"beginResizeHandlerEvent($event)\"\r\n (resizingHandlerEvent)=\"onResizingFixedHandler($event)\"\r\n [fixHeader]=\"fixHeader\"\r\n (dragTableEndEvent)=\"handleDragTable($event)\"\r\n [dataSource]=\"dataSource\"\r\n [colDropFreezeTo]=\"colDropFreezeTo\"\r\n [colDraggable]=\"colDraggable\"\r\n [childrenTableOpen]=\"childrenTableOpen\"\r\n ></thead>\r\n</ng-template>\r\n<ng-template #HeaderContent><ng-content select=\"thead\"></ng-content></ng-template>\r\n", styles: [".devui-font-size-base{font-size:var(--devui-font-size, 12px)}.devui-font-base{font-size:var(--devui-font-size, 12px);font-weight:var(--devui-font-content-weight, normal);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-modal-title{font-size:var(--devui-font-size-modal-title, 18px)}.devui-font-modal-title{font-size:var(--devui-font-size-modal-title, 18px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-page-title{font-size:var(--devui-font-size-page-title, 16px)}.devui-font-page-title{font-size:var(--devui-font-size-page-title, 16px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-secondary-title{font-size:var(--devui-font-size-card-title, 14px)}.devui-font-secondary-title{font-size:var(--devui-font-size-card-title, 14px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}:host{display:block}:host.devui-table-shadow{border-radius:var(--devui-border-radius-card, 6px);box-shadow:var(--devui-shadow-length-base, 0 1px 6px 0) var(--devui-light-shadow, rgba(0, 0, 0, .08));background-color:var(--devui-base-bg, #ffffff)}:host.devui-table-shadow ::ng-deep table tbody tr:last-child td{border-bottom-color:transparent}.devui-data-table ::ng-deep{border:none;height:100%}.devui-data-table ::ng-deep .devui-table-view{padding:0;border:none;position:relative;height:100%;z-index:1}.devui-data-table ::ng-deep .devui-table-view.contain-fix-height{display:flex;flex-direction:column}.devui-data-table ::ng-deep .devui-table-view.contain-fix-height .scroll-view{flex:1}.devui-data-table ::ng-deep .devui-table-view.has-width-scroll:not(:hover):not(:has(.table-row-selected)):after{content:\"\";position:absolute;right:0;bottom:0;top:0;width:50px;z-index:100;background:linear-gradient(90deg,transparent,var(--devui-base-bg, #ffffff))}.devui-data-table ::ng-deep .devui-table-view.has-height-scroll:not(:hover):before{content:\"\";position:absolute;left:0;bottom:0;right:0;z-index:100;height:20px;background:linear-gradient(180deg,transparent,var(--devui-base-bg, #ffffff))}.devui-data-table ::ng-deep .devui-table-view .scroll-view{overflow-x:auto;overflow-y:scroll}.devui-data-table ::ng-deep .devui-table-view .scroll-view.overflow-overlay.table-wrap{overflow:auto}.devui-data-table ::ng-deep .devui-table-view .scroll-view.overflow-overlay::-webkit-scrollbar-thumb{background-color:transparent}.devui-data-table ::ng-deep .devui-table-view .scroll-view.overflow-overlay:hover::-webkit-scrollbar-thumb{background-color:var(--devui-line, #dbdbdb)}.devui-data-table ::ng-deep .devui-table-view .scroll-view.overflow-overlay:hover::-webkit-scrollbar-thumb:hover{background-color:var(--devui-placeholder, #808080)}.devui-data-table ::ng-deep .devui-table-view .devui-table{border-collapse:separate;border-spacing:0;table-layout:fixed;width:100%;max-width:100%;margin:0}.devui-data-table ::ng-deep .devui-table-view .devui-table>tbody+tbody{border-top:none}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper{overflow-x:auto;overflow-y:scroll;position:relative}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.overflow-overlay.virtual-scroll-wrap{overflow:auto}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.overflow-overlay::-webkit-scrollbar-thumb{background-color:transparent}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.overflow-overlay:hover::-webkit-scrollbar-thumb{background-color:var(--devui-line, #dbdbdb)}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.overflow-overlay:hover::-webkit-scrollbar-thumb:hover{background-color:var(--devui-placeholder, #808080)}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.has-width-scroll:not(:hover):after{content:\"\";position:absolute;right:0;bottom:0;top:0;width:50px;background:linear-gradient(90deg,transparent,#ffffff)}.devui-data-table ::ng-deep .devui-table-view .viewport-wrapper.has-height-scroll:not(:hover):before{content:\"\";position:absolute;left:0;bottom:0;right:0;height:20px;background:linear-gradient(180deg,transparent,#ffffff)}.devui-data-table ::ng-deep .devui-table-view .resize-bar{top:0;bottom:0;position:absolute;cursor:col-resize;background:var(--devui-form-control-line-active, #0a59f7);width:2px;z-index:9999;display:none}.devui-data-table ::ng-deep .devui-table-view .resize-overlay{position:absolute;display:block;top:0;left:0;bottom:0!important;right:0;z-index:1000}.devui-data-table ::ng-deep .table-wrap{overflow-y:auto}.devui-data-table ::ng-deep .virtual-scroll-wrap .cdk-virtual-scroll-content-wrapper{padding-top:8px}.devui-table ::ng-deep thead tr{background-color:var(--devui-base-bg, #ffffff)}.devui-table ::ng-deep thead tr th{text-align:left;background-clip:padding-box!important;border-bottom:1px solid var(--devui-dividing-line, #f0f0f0);display:table-cell;padding:0;font-size:0;background-color:inherit}.devui-table ::ng-deep thead tr th .drag-icon{display:inline-block;margin-right:2px;visibility:hidden}.devui-table ::ng-deep thead tr th .drag-icon+.childtable-toggler>.customized-icon{font-size:var(--devui-font-size-icon, 16px)}.devui-table ::ng-deep thead tr th>*{display:inline-block}.devui-table ::ng-deep thead