Created
November 26, 2022 23:49
-
-
Save pjlamb12/6b0382793ee192d2b9007e11eed0a969 to your computer and use it in GitHub Desktop.
Angular Data Table Component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<content-section | |
[csTitle]="title" | |
[collapsible]="collapsible" | |
[state]="state" | |
[locked]="locked" | |
[noButtons]="noButtons" | |
[buttons]="_buttons" | |
> | |
<!-- Custom controls --> | |
<ng-content></ng-content> | |
<!-- Filter radio --> | |
<div class="top-bar"> | |
<div *ngIf="filtersExist()"> | |
<mat-radio-group [(ngModel)]="show" (change)="filterRadioChanged($event)"> | |
Show: | |
<mat-radio-button | |
*ngFor="let filter of filters" | |
[value]="filter.value" | |
(change)="setFilterValue(filter.value)" | |
> | |
{{ filter.text }}</mat-radio-button | |
> | |
</mat-radio-group> | |
</div> | |
<div class="right"> | |
<div *ngIf="showStartDate"> | |
<p class="date-picker-name">{{ startDateName }}</p> | |
<highlighted-datepicker | |
[control]="startDateControl" | |
(dateChange)="changeStartDate($event)" | |
#startDate | |
> | |
</highlighted-datepicker> | |
</div> | |
<div *ngIf="showEndDate"> | |
<p class="date-picker-name">{{ endDateName }}</p> | |
<highlighted-datepicker | |
[control]="endDateControl" | |
(dateChange)="changeEndDate($event)" | |
#endDate | |
> | |
</highlighted-datepicker> | |
</div> | |
</div> | |
</div> | |
<!-- Filter Checkbox --> | |
<div class="top-bar"> | |
<div *ngIf="checkboxFilterInput"> | |
<mat-checkbox | |
[checked]="checkboxFilterInput.checked" | |
(change)="changeCheckboxFilter()" | |
> | |
{{ checkboxFilterInput.label }} | |
</mat-checkbox> | |
</div> | |
</div> | |
<!-- Search controls --> | |
<ct-search | |
#search | |
(searchTermsChange)="applyFilter(); applyTextFilter($event)" | |
[fieldsToSearch]="searchFields" | |
[enableDebounce]="true" | |
(selectTopResult)="runDefaultOnTopResult()" | |
[searchTerms]="textSearchTerms" | |
></ct-search> | |
<!-- Mass actions & column selector --> | |
<div class="mass-container" #scrollView> | |
<div class="mass-actions" *ngIf="massActionsExist()"> | |
<ng-container *ngFor="let action of getMassActions()"> | |
<span [matTooltip]="action.tooltip(selection.selected)"> | |
<button | |
mat-button | |
class="mass-buttons" | |
(click)="massChanges(action)" | |
[@massButtons]="selection.hasValue() ? 'enabled' : 'disabled'" | |
[disabled]="!action.enabled(selection.selected)" | |
[color]="action.color" | |
[class]="action.color ? '' : action.customClass" | |
> | |
{{ action.buttonText.toUpperCase() }} | |
</button> | |
</span> | |
</ng-container> | |
</div> | |
<span class="fill-flex"></span> | |
<column-selector | |
#columnSelector | |
[persistentStorageName]="storageName" | |
[dataSource]="dataSource" | |
[defaultColumnList]="columns" | |
[defaultPageSize]="pageSize" | |
></column-selector> | |
</div> | |
<responsive-table> | |
<div class="loading-overlay" *ngIf="isLoading"> | |
<p>Loading...</p> | |
<mat-spinner mode="indeterminate" diameter="70"></mat-spinner> | |
</div> | |
<mat-table | |
[ngClass]="{ 'no-data': dataSource.filteredData.length === 0 }" | |
#table | |
[dataSource]="dataSource" | |
#sort="matSort" | |
matSort | |
> | |
<!--Bulk selections--> | |
<ng-container | |
class="checkBox" | |
matColumnDef="checkBoxes" | |
*ngIf="massActionsExist()" | |
> | |
<mat-header-cell *matHeaderCellDef> | |
<mat-checkbox | |
(change)="$event ? masterToggle() : null" | |
[checked]="selection.hasValue() && isAllSelected()" | |
[indeterminate]="selection.hasValue() && !isAllSelected()" | |
[aria-label]="checkboxLabel()" | |
> | |
</mat-checkbox> | |
</mat-header-cell> | |
<mat-cell *matCellDef="let row" (click)="$event.stopPropagation()"> | |
<mat-checkbox | |
(click)="$event.stopPropagation()" | |
(change)="$event ? selection.toggle(row) : null" | |
[checked]="selection.isSelected(row)" | |
[aria-label]="checkboxLabel(row)" | |
> | |
</mat-checkbox> | |
</mat-cell> | |
</ng-container> | |
<!-- Column definitions --> | |
<ng-container *ngFor="let col of columns" [matColumnDef]="col.column_key"> | |
<mat-header-cell *matHeaderCellDef mat-sort-header | |
>{{ columnTitle(col) }}</mat-header-cell | |
> | |
<ng-container *ngIf="col.routerLink !== null && col.innerHTML === null"> | |
<mat-cell *matCellDef="let row" class="wrap-words"> | |
<a | |
[routerLink]="col.routerLink(row)" | |
[innerHtml]="col.contents(row)" | |
></a> | |
</mat-cell> | |
</ng-container> | |
<ng-container *ngIf="col.component === null && col.innerHTML === null"> | |
<mat-cell *matCellDef="let row" class="wrap-words" | |
>{{ col.contents(row) }}</mat-cell | |
> | |
</ng-container> | |
<ng-container *ngIf="col.component !== null"> | |
<mat-cell *matCellDef="let row" class="wrap-words"> | |
<custom-cell [component]="col.component" [row]="row"></custom-cell> | |
</mat-cell> | |
</ng-container> | |
<ng-container *ngIf="col.component === null && col.innerHTML !== null"> | |
<mat-cell | |
*matCellDef="let row" | |
class="wrap-words" | |
[innerHtml]="col.innerHTML(row)" | |
></mat-cell> | |
</ng-container> | |
</ng-container> | |
<!-- Action buttons --> | |
<ng-container *ngIf="actionsExist()" matColumnDef="actions"> | |
<mat-header-cell *matHeaderCellDef>Actions</mat-header-cell> | |
<mat-cell *matCellDef="let i = index; let row"> | |
<!-- Buttons outside of the dropdown menu --> | |
<div class="action-buttons"> | |
<ng-container *ngFor="let button of getButtonActions(row)"> | |
<span [matTooltip]="button.tooltip(row)"> | |
<a | |
mat-button | |
appRowButton | |
*ngIf="button.href(row) !== null" | |
[href]="button.href(row)" | |
[color]="row | buttonColor: button" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event.stopPropagation())" | |
[class]="button.customClass(row)" | |
[highlight]="button.isDefaultAction && rowIndex === i && !btnHovered" | |
[disabled]="!button.enabled(row)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<a | |
mat-button | |
appRowButton | |
*ngIf="button.routerLink(row) !== null" | |
[routerLink]="button.routerLink(row)" | |
[queryParams]="button.queryParams(row)" | |
[color]="row | buttonColor: button" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event.stopPropagation())" | |
[class]="button.customClass(row)" | |
[highlight]="button.isDefaultAction && rowIndex === i && !btnHovered" | |
[disabled]="!button.enabled(row)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<button | |
mat-button | |
appRowButton | |
*ngIf="button.routerLink(row) === null && button.href(row) === null" | |
[color]="row | buttonColor: button" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
[class]="button.customClass(row)" | |
[highlight]="button.isDefaultAction && rowIndex === i && !btnHovered" | |
[disabled]="!button.enabled(row)" | |
> | |
{{ button.buttonText }} | |
</button> | |
</span> | |
</ng-container> | |
</div> | |
<!-- Dropdown menu --> | |
<button | |
mat-icon-button | |
*ngIf="menuActionsExist()" | |
[matMenuTriggerFor]="more" | |
(click)="$event.stopPropagation()" | |
appRowButton | |
(hovered)="btnHovered = $event" | |
> | |
<mat-icon>more_vert</mat-icon> | |
</button> | |
<mat-menu #more="matMenu"> | |
<ng-container *ngFor="let button of getMenuActions()"> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.href(row) !== null && button.enabled(row)" | |
[href]="button.href(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.routerLink(row) !== null && button.enabled(row)" | |
[routerLink]="button.routerLink(row)" | |
[queryParams]="button.queryParams(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.href(row) === null && button.routerLink(row) === null && button.enabled(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
</ng-container> | |
<button | |
mat-menu-item | |
*ngFor="let button of hasDropDown()" | |
[matMenuTriggerFor]="dropDowns" | |
> | |
{{ button.buttonText }} | |
</button> | |
</mat-menu> | |
<mat-menu #dropDowns="matMenu"> | |
<ng-container *ngFor="let button of dropDownItems()"> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.href(row) !== null && button.enabled(row)" | |
[href]="button.href(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.routerLink(row) !== null && button.enabled(row)" | |
[routerLink]="button.routerLink(row)" | |
[queryParams]="button.queryParams(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
<a | |
mat-menu-item | |
appRowButton | |
*ngIf="button.href(row) === null && button.routerLink(row) === null && button.enabled(row)" | |
(hovered)="btnHovered = $event" | |
(click)="button.action(row, $event)" | |
> | |
{{ button.buttonText }} | |
</a> | |
</ng-container> | |
</mat-menu> | |
</mat-cell> | |
</ng-container> | |
<!-- Table meta --> | |
<mat-header-row | |
[ngStyle]="showHeaderRow()" | |
*matHeaderRowDef="getColumns()" | |
></mat-header-row> | |
<mat-row | |
[appRowAction]="index" | |
(hovered)="rowIndex = $event" | |
*matRowDef="let row; let index = index; columns: getColumns()" | |
(click)="rowClick(row, $event)" | |
[ngClass]="resolveRowClass(row)" | |
></mat-row> | |
</mat-table> | |
<!-- Search suggestions --> | |
<div class="suggested"> | |
<div | |
class="no-results" | |
*ngIf="!isLoading && dataSource.filteredData.length === 0" | |
> | |
<p>No results found with current filters.</p> | |
</div> | |
</div> | |
</responsive-table> | |
<!-- Paginator --> | |
<div class="table-footer"> | |
<button | |
mat-button | |
[class.hidden]="!paginator.hasNextPage()" | |
class="nextPage" | |
(click)="paginator.nextPage()" | |
> | |
<p class="nxText"> | |
{{ numMoreRows }} More... | |
<span class="nxPage" color="primary"> | |
NEXT PAGE | |
<mat-icon>chevron_right</mat-icon> | |
</span> | |
</p> | |
</button> | |
<mat-paginator | |
#paginator | |
[length]="dataSource.data.length" | |
[pageSize]="pageSize" | |
[pageSizeOptions]="pageSizeOptions" | |
></mat-paginator> | |
</div> | |
</content-section> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
animate, | |
state, | |
style, | |
transition, | |
trigger, | |
} from "@angular/animations"; | |
import { SelectionModel } from "@angular/cdk/collections"; | |
import { | |
AfterViewInit, | |
Component, | |
ElementRef, | |
EventEmitter, | |
Input, | |
OnInit, | |
Output, | |
ViewChild, | |
} from "@angular/core"; | |
import { FormControl } from "@angular/forms"; | |
import { MatDatepickerInputEvent } from "@angular/material/datepicker"; | |
import { MatPaginator, PageEvent } from "@angular/material/paginator"; | |
import { MatRadioChange } from "@angular/material/radio"; | |
import { MatSort } from "@angular/material/sort"; | |
import { MatTableDataSource } from "@angular/material/table"; | |
import { DomSanitizer } from "@angular/platform-browser"; | |
import { Router } from "@angular/router"; | |
import { ColumnSelector } from "app/column-selector/column-selector.component"; | |
import { HighlightedDatepickerComponent } from "app/highlighted-datepicker/highlighted-datepicker.component"; | |
import { NaturalSorter } from "app/shared/natural-sorter.service"; | |
import { | |
SearchComponent, | |
SearchField, | |
SearchTerm, | |
} from "../../search/search.component"; | |
import { ContentSectionButton } from "../../shared/content-section/content-section-button"; | |
import { UserSession } from "../../shared/user-session.service"; | |
import { ActionConfig } from "../action-config"; | |
import { ColumnConfig } from "../column-config"; | |
import { FilterConfig } from "../filter-config"; | |
import { MassActionConfig } from "../mass-action-config"; | |
export const dataTableAnimations = [ | |
trigger("massButtons", [ | |
state( | |
"disabled", | |
style({ | |
transform: "scaleX(0)", | |
}) | |
), | |
state( | |
"enabled", | |
style({ | |
transform: "scaleX(1)", | |
}) | |
), | |
transition("disabled <=> enabled", animate("100ms")), | |
]), | |
]; | |
@Component({ | |
selector: "ct-data-table", | |
templateUrl: "./data-table.component.html", | |
styleUrls: [ | |
"./data-table.component.scss", | |
"../../styles/model-list.component.scss", | |
"../../styles/row-action-list.component.scss", | |
], | |
}) | |
export class DataTable implements OnInit, AfterViewInit { | |
//////////////////////////////////////////////////////////////////// | |
// ContentSection variables | |
//////////////////////////////////////////////////////////////////// | |
@Input("csTitle") title = "Title"; | |
@Input() collapsible: any = false; | |
@Input() state: "open" | "closed" = "open"; | |
@Input() locked: false; | |
@Input() noButtons = false; | |
public _buttons = new Array<ContentSectionButton>(); | |
@Input() | |
set buttons(buttons: Array<ContentSectionButton> | ContentSectionButton) { | |
if (buttons == null) { | |
return; | |
} | |
if (buttons.constructor !== Array) { | |
buttons = [buttons as ContentSectionButton]; | |
} | |
this._buttons = buttons as Array<ContentSectionButton>; | |
} | |
get buttons() { | |
return this.noButtons ? [] : this._buttons; | |
} | |
//////////////////////////////////////////////////////////////////// | |
// Date range picker variables | |
//////////////////////////////////////////////////////////////////// | |
@ViewChild("startDate", { static: true }) | |
startDatePicker: HighlightedDatepickerComponent; | |
@Input() showStartDate = false; | |
@Input() startDateName = "Start Date"; | |
@Output() startDateChanged = new EventEmitter(); | |
@Input() startDateControl = new FormControl(Date()); | |
@ViewChild("endDate", { static: true }) | |
endDatePicker: HighlightedDatepickerComponent; | |
@Input() showEndDate = false; | |
@Input() endDateName = "End Date"; | |
@Output() endDateChanged = new EventEmitter(); | |
@Input() endDateControl = new FormControl(Date()); | |
//////////////////////////////////////////////////////////////////// | |
// Data table variables | |
//////////////////////////////////////////////////////////////////// | |
@Input() filters: Array<FilterConfig<any>> = []; | |
@Output() filterChanged = new EventEmitter(); | |
@Output() textFilterChanged: EventEmitter<Array<SearchTerm>> = | |
new EventEmitter<Array<SearchTerm>>(); | |
@Input() textSearchTerms: SearchTerm[] = []; | |
@Input() columns: Array<ColumnConfig<any>>; | |
@Input() actions: Array<ActionConfig<any>> = []; | |
@Input() massActions: Array<MassActionConfig<any>> = []; | |
@Input() defaultAction: (row: any) => void = () => {}; | |
@Input() storageName: string; | |
@Input() resolveRowClass: (row: any) => string = () => null; | |
@Input() rowIndex: number; | |
@Input() btnHovered: boolean; | |
@Input() focusTopResult = false; | |
@Input() checkboxFilterInput: any; | |
@Output() checkboxFilterChange = new EventEmitter(); | |
@Input() show = ""; | |
@Input() dataSource: MatTableDataSource<any>; | |
public selection = new SelectionModel<any>(true, []); | |
public filterPosition: string; | |
@Input() isLoading = false; | |
@Input() pageSize = 50; | |
@Input() pageSizeOptions = [50, 100]; | |
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; | |
@ViewChild(MatSort, { static: true }) sort: MatSort; | |
@ViewChild("search", { static: true }) searchComponent: SearchComponent; | |
@ViewChild("columnSelector", { static: true }) columnSelector: ColumnSelector; | |
@ViewChild("scrollView", { read: ElementRef, static: true }) | |
scrollViewElement: ElementRef; | |
//////////////////////////////////////////////////////////////////// | |
// Constructor and initialization | |
//////////////////////////////////////////////////////////////////// | |
constructor( | |
// eslint-disable-next-line @typescript-eslint/no-unused-vars | |
private router: Router, | |
private sanitizer: DomSanitizer, | |
private session: UserSession, | |
private naturalSorter: NaturalSorter | |
) { | |
const startDate = new Date(); | |
startDate.setDate(startDate.getDate() - 30); | |
this.startDateControl = new FormControl(startDate); | |
this.endDateControl = new FormControl(new Date()); | |
} | |
ngOnInit() { | |
if (this.filters.length > 0) { | |
this.show = this.filters.find((f) => f.checked).value; | |
this.filterPosition = this.show; | |
} | |
this.paginator.page.subscribe((event: PageEvent) => { | |
if (event.previousPageIndex !== event.pageIndex) { | |
setTimeout(() => { | |
this.scrollViewElement.nativeElement.scrollIntoView({ | |
behavior: "smooth", | |
block: "start", | |
}); | |
}); | |
} | |
this.clearSelection(); | |
}); | |
} | |
ngAfterViewInit() { | |
this.dataSource.paginator = this.paginator; | |
this.dataSource.sort = this.sort; | |
this.dataSource.sortingDataAccessor = (row, property) => { | |
const key = | |
this.columns.find((c) => c.column_key === property).searchKey(row) ?? | |
""; | |
return typeof key === "string" ? key?.toLowerCase() : key; | |
}; | |
this.dataSource.sortData = (data: Array<any>, sort: MatSort) => { | |
if (!sort.active || sort.direction === "") { | |
return data; | |
} | |
return data.sort((a, b) => { | |
const first = this.dataSource.sortingDataAccessor(a, sort.active); | |
const second = this.dataSource.sortingDataAccessor(b, sort.active); | |
return ( | |
this.naturalSorter.sort(first, second) * | |
(sort.direction === "asc" ? 1 : -1) | |
); | |
}); | |
}; | |
this.dataSource.filterPredicate = (row: any, _filter: string) => { | |
const terms = this.searchComponent.searchTerms; | |
const fields = this.searchComponent.fieldsToSearch.map((f) => f.value); | |
const scope = this.filters.find((f) => f.value === this.show); | |
if (scope != null && scope.filterFn(row) === false) { | |
return false; | |
} | |
const accumulator = (accumulatingTerms: string, key: string, _e: any) => { | |
return ( | |
accumulatingTerms + | |
(this.columns.find((c) => c.column_key === key).searchKey(row) ?? "") | |
); | |
}; | |
for (const term of terms) { | |
if (term.term == null) { | |
continue; | |
} | |
if (term.field !== "<all>") { | |
if ( | |
![term.field] | |
.reduce(accumulator, "") | |
.toLowerCase() | |
.includes(term.term.toLowerCase()) | |
) { | |
return false; | |
} | |
} else { | |
const str = fields.reduce(accumulator, "").toLowerCase(); | |
if (!str.includes(term.term.toLowerCase())) { | |
return false; | |
} | |
} | |
} | |
return true; | |
}; | |
this.applyFilter(); | |
} | |
/** | |
* Call this method at the end of your Synchronizer.appIsReady callback if any reprocessing is required | |
* (e.g. for org-configurable accounting codes fields). | |
*/ | |
public notifyColumnConfigsCalculationFinished() { | |
this.columnSelector.savedList = this.columnSelector.savedList.filter( | |
(col) => { | |
const match = this.columns.find((x) => x.column_key === col.column_key); | |
return match.isEnabled(); | |
} | |
); | |
this.columnSelector.currentList = this.columnSelector.currentList.filter( | |
(col) => { | |
const match = this.columns.find((x) => x.column_key === col.column_key); | |
return match.isEnabled(); | |
} | |
); | |
this.columnSelector.currentList.forEach((col) => { | |
if (col.name === "") { | |
const match = this.columns.find((x) => x.column_key === col.column_key); | |
col.name = match.name; | |
} | |
}); | |
} | |
//////////////////////////////////////////////////////////////////// | |
// Methods used in the template | |
//////////////////////////////////////////////////////////////////// | |
public applyFilter(): void { | |
this.dataSource.filter = "_"; | |
} | |
public applyTextFilter(filters: SearchTerm[]) { | |
this.textFilterChanged.emit(filters); | |
} | |
public runDefaultOnTopResult(): void { | |
if (this.dataSource.filteredData.length !== 0 && this.focusTopResult) { | |
const organization = this.dataSource.filteredData[0]; | |
this.defaultAction(organization); | |
} | |
} | |
public filterRadioChanged(event: MatRadioChange): void { | |
this.filterChanged.emit(event.value); | |
this.applyFilter(); | |
} | |
get searchFields(): Array<SearchField> { | |
return this.columns.filter((c) => c.searchField === true && c.isEnabled()); | |
} | |
public getColumns() { | |
const Cols = this.columnSelector.currentList | |
.filter( | |
(c) => | |
c.selected && | |
this.columns | |
.find((col) => col.column_key === c.column_key) | |
.isEnabled() | |
) | |
.map((c) => c.column_key); | |
if (this.actionsExist()) { | |
Cols.push("actions"); | |
} | |
if (this.massActionsExist()) { | |
Cols.unshift("checkBoxes"); | |
} | |
return Cols; | |
} | |
public showHeaderRow() { | |
return { | |
display: `${this.dataSource.filteredData.length !== 0 ? "" : "none"}`, | |
}; | |
} | |
public columnTitle(column: ColumnConfig<any>): string { | |
return column.showTitle ? column.name : ""; | |
} | |
public filtersExist() { | |
return this.filters.length > 0; | |
} | |
public actionsExist() { | |
return this.actions.length > 0; | |
} | |
public getButtonActions(row: any) { | |
return this.actions.filter((a) => { | |
return ( | |
!a.inMenu && a.restrictToUserType <= (this.session.UserType?.id ?? -1) | |
); | |
}); | |
} | |
public menuActionsExist() { | |
return ( | |
this.actions.filter( | |
(a) => a.inMenu && a.restrictToUserType <= this.session.UserType.id | |
).length > 0 | |
); | |
} | |
public massActionsExist() { | |
return ( | |
this.massActions.filter( | |
(x) => x.restrictToUserType <= this.session.UserType.id | |
).length > 0 | |
); | |
} | |
public getMassActions() { | |
return this.massActions.filter( | |
(x) => !x.hidden() && x.restrictToUserType <= this.session.UserType.id | |
); | |
} | |
public getMenuActions() { | |
return this.actions.filter( | |
(a) => | |
a.inMenu && | |
a.subMenuItems.length === 0 && | |
a.restrictToUserType <= this.session.UserType.id | |
); | |
} | |
public hasDropDown() { | |
return this.actions.filter( | |
(a) => | |
a.subMenuItems.length > 0 && | |
a.restrictToUserType <= this.session.UserType.id | |
); | |
} | |
public dropDownItems() { | |
let enabledDropDowns = new Array<ActionConfig<any>>(); | |
this.actions | |
.filter( | |
(a) => | |
a.subMenuItems.length > 0 && | |
a.enabled() && | |
a.restrictToUserType <= this.session.UserType.id | |
) | |
.map((action) => { | |
enabledDropDowns = action.subMenuItems.filter( | |
(a) => a.enabled() && a.restrictToUserType <= this.session.UserType.id | |
); | |
}); | |
return enabledDropDowns; | |
} | |
public rowClick(row: any, event: MouseEvent) { | |
const selection = event.view.getSelection(); | |
if (selection.type !== "Range") { | |
this.defaultAction(row); | |
} | |
} | |
public setFilterValue(f: string) { | |
this.selection.clear(); | |
this.filterPosition = f; | |
} | |
public isAllSelected() { | |
const numSelected = this.selection.selected.length; | |
const rowData = this.dataSource.connect().value; | |
return numSelected === rowData.length; | |
} | |
public masterToggle() { | |
const displayedData = this.dataSource.connect().value; | |
this.isAllSelected() | |
? this.selection.clear() | |
: displayedData.forEach((row) => this.selection.select(row)); | |
} | |
public checkboxLabel(row?: any): string { | |
if (!row) { | |
return `${this.isAllSelected() ? "select" : "deselect"} all`; | |
} | |
return `${this.selection.isSelected(row) ? "deselect" : "select"} row ${ | |
row.position + 1 | |
}`; | |
} | |
public massChanges(buttonConfig: MassActionConfig<any>) { | |
buttonConfig.action(this.selection.selected); | |
} | |
public clearSelection(): void { | |
this.selection.clear(); | |
} | |
public get numMoreRows(): number { | |
const paginator = this.dataSource.paginator; | |
if (paginator == null) { | |
return 0; | |
} | |
return Math.max( | |
paginator.length - paginator.pageSize * (paginator.pageIndex + 1), | |
0 | |
); | |
} | |
public changeStartDate(event: MatDatepickerInputEvent<Date>): void { | |
this.startDateControl.setValue(event.value); | |
this.startDateChanged.emit(event.value); | |
} | |
public changeEndDate(event: MatDatepickerInputEvent<Date>): void { | |
this.endDateControl.setValue(event.value); | |
this.endDateChanged.emit(event.value); | |
} | |
public changeCheckboxFilter() { | |
this.checkboxFilterChange.emit(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment