@clr/angular
Version:
Angular components for Clarity
556 lines • 102 kB
JavaScript
/*
* Copyright (c) 2016-2025 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
import { DOCUMENT } from '@angular/common';
import { Component, ContentChild, ContentChildren, ElementRef, EventEmitter, Inject, Input, Output, ViewChild, ViewChildren, ViewContainerRef, } from '@angular/core';
import { combineLatest, fromEvent, merge, of } from 'rxjs';
import { debounceTime, switchMap } from 'rxjs/operators';
import { uniqueIdFactory } from '../../utils/id-generator/id-generator.service';
import { ClrDatagridColumn } from './datagrid-column';
import { ClrDatagridItems } from './datagrid-items';
import { ClrDatagridPlaceholder } from './datagrid-placeholder';
import { ClrDatagridRow } from './datagrid-row';
import { ClrDatagridVirtualScrollDirective } from './datagrid-virtual-scroll.directive';
import { DatagridDisplayMode } from './enums/display-mode.enum';
import { SelectionType } from './enums/selection-type';
import { ColumnsService } from './providers/columns.service';
import { DetailService } from './providers/detail.service';
import { DisplayModeService } from './providers/display-mode.service';
import { FiltersProvider } from './providers/filters';
import { ExpandableRowsCount } from './providers/global-expandable-rows';
import { Items } from './providers/items';
import { Page } from './providers/page';
import { RowActionService } from './providers/row-action-service';
import { Selection } from './providers/selection';
import { Sort } from './providers/sort';
import { StateDebouncer } from './providers/state-debouncer.provider';
import { StateProvider } from './providers/state.provider';
import { TableSizeService } from './providers/table-size.service';
import { DatagridRenderOrganizer } from './render/render-organizer';
import { KeyNavigationGridController } from './utils/key-navigation-grid.controller';
import * as i0 from "@angular/core";
import * as i1 from "./render/render-organizer";
import * as i2 from "./providers/items";
import * as i3 from "./providers/global-expandable-rows";
import * as i4 from "./providers/selection";
import * as i5 from "./providers/row-action-service";
import * as i6 from "./providers/state.provider";
import * as i7 from "./providers/display-mode.service";
import * as i8 from "./providers/detail.service";
import * as i9 from "./providers/page";
import * as i10 from "../../utils/i18n/common-strings.service";
import * as i11 from "./utils/key-navigation-grid.controller";
import * as i12 from "@angular/common";
import * as i13 from "../../forms/common/label";
import * as i14 from "@angular/forms";
import * as i15 from "../../progress/spinner/spinner";
import * as i16 from "./datagrid-cell";
import * as i17 from "./datagrid-placeholder";
import * as i18 from "./datagrid-row";
import * as i19 from "./datagrid-selection-cell.directive";
import * as i20 from "./render/cell-renderer";
import * as i21 from "./render/row-renderer";
import * as i22 from "./chocolate/actionable-oompa-loompa";
import * as i23 from "./chocolate/expandable-oompa-loompa";
export class ClrDatagrid {
constructor(organizer, items, expandableRows, selection, rowActionService, stateProvider, displayMode, renderer, detailService, document, el, page, commonStrings, keyNavigation, zone) {
this.organizer = organizer;
this.items = items;
this.expandableRows = expandableRows;
this.selection = selection;
this.rowActionService = rowActionService;
this.stateProvider = stateProvider;
this.displayMode = displayMode;
this.renderer = renderer;
this.detailService = detailService;
this.document = document;
this.el = el;
this.page = page;
this.commonStrings = commonStrings;
this.keyNavigation = keyNavigation;
this.zone = zone;
this.clrDgSingleSelectionAriaLabel = this.commonStrings.keys.singleSelectionAriaLabel;
this.clrDgSingleActionableAriaLabel = this.commonStrings.keys.singleActionableAriaLabel;
this.clrDetailExpandableAriaLabel = this.commonStrings.keys.detailExpandableAriaLabel;
// Allows disabling of the auto focus on page/state changes (excludes focus management inside of popups)
this.clrDgDisablePageFocus = false;
this.selectedChanged = new EventEmitter(false);
this.singleSelectedChanged = new EventEmitter(false);
/**
* Output emitted whenever the data needs to be refreshed, based on user action or external ones
*/
this.refresh = new EventEmitter(false);
/**
* The application can provide custom select all logic.
*/
this.customSelectAllEnabled = false;
this.customSelectAll = new EventEmitter();
/* reference to the enum so that template can access */
this.SELECTION_TYPE = SelectionType;
/**
* Subscriptions to all the services and queries changes
*/
this._subscriptions = [];
this._virtualScrollSubscriptions = [];
this.cachedRowsHeight = 0;
this.cachedContentHeight = 0;
this.resizeObserver = new ResizeObserver(entries => {
requestAnimationFrame(() => {
this.handleResizeChanges(entries);
});
});
const datagridId = uniqueIdFactory();
this.selectAllId = 'clr-dg-select-all-' + datagridId;
detailService.id = datagridId;
}
/**
* Freezes the datagrid while data is loading
*/
get loading() {
return this.items.loading;
}
set loading(value) {
this.items.loading = value;
}
/**
* Array of all selected items
*/
set selected(value) {
if (value) {
this.selection.selectionType = SelectionType.Multi;
}
else {
this.selection.selectionType = SelectionType.None;
}
this.selection.updateCurrent(value, false);
}
/**
* Selected item in single-select mode
*/
set singleSelected(value) {
this.selection.selectionType = SelectionType.Single;
// the clrDgSingleSelected is updated in one of two cases:
// 1. an explicit value is passed
// 2. is being set to null or undefined, where previously it had a value
if (value) {
this.selection.currentSingle = value;
}
else if (this.selection.currentSingle) {
this.selection.currentSingle = null;
}
}
set clrDgPreserveSelection(state) {
this.selection.preserveSelection = state;
}
/**
* @deprecated since 2.0, remove in 3.0
*
* Selection/Deselection on row click mode
*/
set rowSelectionMode(value) {
this.selection.rowSelectionMode = value;
}
set trackBy(value) {
this.items.trackBy = value;
}
/**
* Indicates if all currently displayed items are selected
*/
get allSelected() {
return this.selection.isAllSelected();
}
set allSelected(value) {
if (this.customSelectAllEnabled) {
this.customSelectAll.emit(value);
}
else {
/**
* This is a setter but we ignore the value.
* It's strange, but it lets us have an indeterminate state where only
* some of the items are selected.
*/
this.selection.toggleAll();
}
}
get virtualScroll() {
return this._virtualScroll?.get(0);
}
ngAfterContentInit() {
if (!this.items.smart) {
this.items.all = this.rows.map((row) => row.item);
}
const rowItemsChanges = this.rows.changes.pipe(switchMap((rows) => merge(
// immediate update
of(rows.map(row => row.item)),
// subsequent updates once per tick
combineLatest(rows.map(row => row.itemChanges)).pipe(debounceTime(0)))));
this._subscriptions.push(rowItemsChanges.subscribe(all => {
if (!this.items.smart) {
this.items.all = all;
}
}), this._virtualScroll.changes.subscribe(() => {
this.toggleVirtualScrollSubscriptions();
}), this.rows.changes.subscribe(() => {
// Remove any projected rows from the displayedRows container
// Necessary with Ivy off. See https://github.com/vmware/clarity/issues/4692
for (let i = this._displayedRows.length - 1; i >= 0; i--) {
if (this._displayedRows.get(i).destroyed) {
this._displayedRows.remove(i);
}
}
this.rows.forEach(row => {
this._displayedRows.insert(row._view);
});
this.updateDetailState();
// retain active cell when navigating with Up/Down Arrows, PageUp and PageDown buttons in virtual scroller
if (this.virtualScroll && this.activeCellCoords) {
this.zone.runOutsideAngular(() => {
const row = Array.from(this.rows).find(row => {
return row.el.nativeElement.children[0].ariaRowIndex === this.activeCellCoords.ariaRowIndex;
});
if (!row) {
return;
}
const activeCell = row.el.nativeElement.querySelectorAll(this.keyNavigation.config.keyGridCells)[this.activeCellCoords.x];
this.keyNavigation.setActiveCell(activeCell);
this.keyNavigation.focusElement(activeCell, { preventScroll: true });
});
}
}));
}
/**
* Our setup happens in the view of some of our components, so we wait for it to be done before starting
*/
ngAfterViewInit() {
this.keyNavigation.initializeKeyGrid(this.el.nativeElement);
this.updateDetailState();
// TODO: determine if we can get rid of provider wiring in view init so that subscriptions can be done earlier
this.refresh.emit(this.stateProvider.state);
this._subscriptions.push(this.stickyHeaders.changes.subscribe(() => this.resize()), this.stateProvider.change.subscribe(state => this.refresh.emit(state)), this.selection.change.subscribe(s => {
if (this.selection.selectionType === SelectionType.Single) {
this.singleSelectedChanged.emit(s);
}
else if (this.selection.selectionType === SelectionType.Multi) {
this.selectedChanged.emit(s);
}
}),
// Reinitialize arrow key navigation on page changes
this.page.change.subscribe(() => {
this.keyNavigation.resetKeyGrid();
if (!this.clrDgDisablePageFocus) {
this.datagridTable.nativeElement.focus();
}
}),
// A subscription that listens for displayMode changes on the datagrid
this.displayMode.view.subscribe(viewChange => {
// Remove any projected columns from the projectedDisplayColumns container
for (let i = this._projectedDisplayColumns.length; i > 0; i--) {
this._projectedDisplayColumns.detach();
}
// Remove any projected columns from the projectedCalculationColumns container
for (let i = this._projectedCalculationColumns.length; i > 0; i--) {
this._projectedCalculationColumns.detach();
}
// Remove any projected rows from the calculationRows container
for (let i = this._calculationRows.length; i > 0; i--) {
this._calculationRows.detach();
}
// Remove any projected rows from the displayedRows container
for (let i = this._displayedRows.length; i > 0; i--) {
this._displayedRows.detach();
}
if (viewChange === DatagridDisplayMode.DISPLAY) {
// Set state, style for the datagrid to DISPLAY and insert row & columns into containers
this.renderer.removeClass(this.el.nativeElement, 'datagrid-calculate-mode');
this.columns.forEach(column => {
this._projectedDisplayColumns.insert(column._view);
});
this.rows.forEach(row => {
this._displayedRows.insert(row._view);
});
}
else {
// Set state, style for the datagrid to CALCULATE and insert row & columns into containers
this.renderer.addClass(this.el.nativeElement, 'datagrid-calculate-mode');
// Inserts a fixed column if any of these conditions are true.
const fixedColumnConditions = [
this.rowActionService.hasActionableRow,
this.selection.selectionType !== this.SELECTION_TYPE.None,
this.expandableRows.hasExpandableRow || this.detailService.enabled,
];
fixedColumnConditions
.filter(Boolean)
.forEach(() => this._projectedCalculationColumns.insert(this._fixedColumnTemplate.createEmbeddedView(null)));
this.columns.forEach(column => {
this._projectedCalculationColumns.insert(column._view);
});
this.rows.forEach(row => {
this._calculationRows.insert(row._view);
});
}
}));
if (this.virtualScroll) {
this.toggleVirtualScrollSubscriptions();
}
// We need to preserve shift state, so it can be used on selection change, regardless of the input event
// that triggered the change. This helps us to easily resolve the k/b only case together with the mouse selection case.
this.zone.runOutsideAngular(() => {
this._subscriptions.push(fromEvent(this.document.body, 'keydown').subscribe((event) => {
if (event.key === 'Shift') {
this.selection.shiftPressed = true;
}
}), fromEvent(this.document.body, 'keyup').subscribe((event) => {
if (event.key === 'Shift') {
this.selection.shiftPressed = false;
}
}));
});
}
ngDoCheck() {
// we track for changes on selection.current because it can happen with pushing items
// instead of overriding the variable
this.selection.checkForChanges();
}
ngOnDestroy() {
this._subscriptions.forEach((sub) => sub.unsubscribe());
this._virtualScrollSubscriptions.forEach((sub) => sub.unsubscribe());
this.resizeObserver.disconnect();
}
toggleAllSelected($event) {
$event.preventDefault();
this.selectAllCheckbox?.nativeElement.click();
}
resize() {
this.organizer.resize();
}
/**
* Checks the state of detail panel and if it's opened then
* find the matching row and trigger the detail panel
*/
updateDetailState() {
// Try to update only when there is something cached and its open.
if (this.detailService.state && this.detailService.isOpen) {
const row = this.rows.find(row => this.items.trackBy(row.item) === this.items.trackBy(this.detailService.state));
/**
* Reopen updated row or close it
*/
if (row) {
this.detailService.open(row.item, row.detailButton.nativeElement);
// always keep open when virtual scroll is available otherwise close it
}
else if (!this.virtualScroll) {
// Using setTimeout to make sure the inner cycles in rows are done
setTimeout(() => {
this.detailService.close();
});
}
}
}
/**
* Public method to re-trigger the computation of displayed items manually
*/
dataChanged() {
this.items.refresh();
}
toggleVirtualScrollSubscriptions() {
const hasVirtualScroll = !!this.virtualScroll;
// the virtual scroll will handle the scrolling
this.keyNavigation.preventScrollOnFocus = hasVirtualScroll;
if (hasVirtualScroll && this._virtualScrollSubscriptions.length === 0) {
// TODO: use `resizeObserver` for all datagrid variants
this.resizeObserver.observe(this.contentWrapper.nativeElement);
this.resizeObserver.observe(this.rowsWrapper.nativeElement);
this._virtualScrollSubscriptions.push(fromEvent(this.contentWrapper.nativeElement, 'scroll').subscribe(() => {
if (this.datagridHeader.nativeElement.scrollLeft !== this.contentWrapper.nativeElement.scrollLeft) {
this.datagridHeader.nativeElement.scrollLeft = this.contentWrapper.nativeElement.scrollLeft;
}
}), fromEvent(this.datagridHeader.nativeElement, 'scroll').subscribe(() => {
if (this.datagridHeader.nativeElement.scrollLeft !== this.contentWrapper.nativeElement.scrollLeft) {
this.contentWrapper.nativeElement.scrollLeft = this.datagridHeader.nativeElement.scrollLeft;
}
}), this.keyNavigation.nextCellCoordsEmitter.subscribe(cellCoords => {
if (!cellCoords?.ariaRowIndex) {
this.activeCellCoords = null;
return;
}
if (cellCoords.ariaRowIndex === this.activeCellCoords?.ariaRowIndex) {
this.activeCellCoords = cellCoords;
return;
}
this.activeCellCoords = cellCoords;
// aria-rowindex is always + 1. Check virtual scroller updateAriaRowIndexes method.
const rowIndex = Number(cellCoords.ariaRowIndex) - 1;
this.virtualScroll.scrollToIndex(rowIndex);
}));
}
else if (!hasVirtualScroll) {
this.resizeObserver.disconnect();
this._virtualScrollSubscriptions.forEach((sub) => sub.unsubscribe());
this._virtualScrollSubscriptions = [];
}
}
handleResizeChanges(entries) {
const rowsWrapper = this.rowsWrapper.nativeElement;
for (const entry of entries) {
if (entry.target === this.contentWrapper.nativeElement) {
this.cachedContentHeight = entry.contentRect.height;
}
if (entry.target === rowsWrapper) {
this.cachedRowsHeight = entry.contentRect.height;
}
}
const scrollClass = 'datagrid-scrollbar-visible';
if (this.cachedRowsHeight > this.cachedContentHeight) {
this.renderer.addClass(rowsWrapper, scrollClass);
}
else {
this.renderer.removeClass(rowsWrapper, scrollClass);
}
}
}
ClrDatagrid.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagrid, deps: [{ token: i1.DatagridRenderOrganizer }, { token: i2.Items }, { token: i3.ExpandableRowsCount }, { token: i4.Selection }, { token: i5.RowActionService }, { token: i6.StateProvider }, { token: i7.DisplayModeService }, { token: i0.Renderer2 }, { token: i8.DetailService }, { token: DOCUMENT }, { token: i0.ElementRef }, { token: i9.Page }, { token: i10.ClrCommonStringsService }, { token: i11.KeyNavigationGridController }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
ClrDatagrid.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagrid, selector: "clr-datagrid", inputs: { loadingMoreItems: ["clrLoadingMoreItems", "loadingMoreItems"], clrDgSingleSelectionAriaLabel: "clrDgSingleSelectionAriaLabel", clrDgSingleActionableAriaLabel: "clrDgSingleActionableAriaLabel", clrDetailExpandableAriaLabel: "clrDetailExpandableAriaLabel", clrDgDisablePageFocus: "clrDgDisablePageFocus", customSelectAllEnabled: ["clrDgCustomSelectAllEnabled", "customSelectAllEnabled"], loading: ["clrDgLoading", "loading"], selected: ["clrDgSelected", "selected"], singleSelected: ["clrDgSingleSelected", "singleSelected"], clrDgPreserveSelection: "clrDgPreserveSelection", rowSelectionMode: ["clrDgRowSelection", "rowSelectionMode"], trackBy: ["clrDgItemsTrackBy", "trackBy"] }, outputs: { selectedChanged: "clrDgSelectedChange", singleSelectedChanged: "clrDgSingleSelectedChange", refresh: "clrDgRefresh", customSelectAll: "clrDgCustomSelectAll" }, host: { properties: { "class.datagrid-host": "true", "class.datagrid-detail-open": "detailService.isOpen", "class.datagrid-virtual-scroll": "!!virtualScroll" } }, providers: [
Selection,
Sort,
FiltersProvider,
Page,
Items,
DatagridRenderOrganizer,
RowActionService,
ExpandableRowsCount,
StateDebouncer,
DetailService,
StateProvider,
TableSizeService,
ColumnsService,
DisplayModeService,
KeyNavigationGridController,
], queries: [{ propertyName: "iterator", first: true, predicate: ClrDatagridItems, descendants: true }, { propertyName: "placeholder", first: true, predicate: ClrDatagridPlaceholder, descendants: true }, { propertyName: "_virtualScroll", predicate: ClrDatagridVirtualScrollDirective }, { propertyName: "columns", predicate: ClrDatagridColumn }, { propertyName: "rows", predicate: ClrDatagridRow, emitDistinctChangesOnly: false }], viewQueries: [{ propertyName: "datagrid", first: true, predicate: ["datagrid"], descendants: true, read: ElementRef }, { propertyName: "datagridTable", first: true, predicate: ["datagridTable"], descendants: true, read: ElementRef }, { propertyName: "datagridHeader", first: true, predicate: ["datagridHeader"], descendants: true, read: ElementRef }, { propertyName: "contentWrapper", first: true, predicate: ["contentWrapper"], descendants: true, read: ElementRef, static: true }, { propertyName: "rowsWrapper", first: true, predicate: ["rowsWrapper"], descendants: true, read: ElementRef, static: true }, { propertyName: "scrollableColumns", first: true, predicate: ["scrollableColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_projectedDisplayColumns", first: true, predicate: ["projectedDisplayColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_projectedCalculationColumns", first: true, predicate: ["projectedCalculationColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_displayedRows", first: true, predicate: ["displayedRows"], descendants: true, read: ViewContainerRef }, { propertyName: "_calculationRows", first: true, predicate: ["calculationRows"], descendants: true, read: ViewContainerRef }, { propertyName: "_fixedColumnTemplate", first: true, predicate: ["fixedColumnTemplate"], descendants: true }, { propertyName: "selectAllCheckbox", first: true, predicate: ["selectAllCheckbox"], descendants: true }, { propertyName: "stickyHeaders", predicate: ["stickyHeader"], descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2016-2025 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<ng-content select=\"clr-dg-action-bar\"></ng-content>\n<div class=\"datagrid-outer-wrapper\">\n <div class=\"datagrid-inner-wrapper\">\n <div class=\"datagrid\" #datagrid [attr.aria-hidden]=\"detailService.isOpen ? true : null\">\n <div class=\"datagrid-table-wrapper\">\n <div role=\"grid\" class=\"datagrid-table\" tabindex=\"-1\" #datagridTable>\n <div role=\"rowgroup\" class=\"datagrid-header\" #datagridHeader>\n <div role=\"row\" class=\"datagrid-row\">\n <div class=\"datagrid-row-master datagrid-row-flex\">\n <div class=\"datagrid-row-sticky\">\n <!--header for datagrid where you can select multiple rows -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-select datagrid-fixed-column\"\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Multi\"\n (keydown.space)=\"toggleAllSelected($event)\"\n >\n <div *ngIf=\"!virtualScroll || customSelectAllEnabled\" class=\"clr-checkbox-wrapper\">\n <!-- We need to move focus and space-key handling to the parent because of keyboard arrow key navigation,\n which is not able to transfer focus directly on the input when focused with the tab key -->\n <input\n #selectAllCheckbox\n type=\"checkbox\"\n [id]=\"selectAllId\"\n [(ngModel)]=\"allSelected\"\n [attr.aria-label]=\"commonStrings.keys.selectAll\"\n tabindex=\"-1\"\n />\n <!-- Usage of class clr-col-null here prevents clr-col-* classes from being added when a datagrid is wrapped inside clrForm -->\n <label [for]=\"selectAllId\" class=\"clr-control-label clr-col-null\">\n <span class=\"clr-sr-only\">{{commonStrings.keys.selectAll}}</span>\n </label>\n </div>\n\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for datagrid where you can select one row only -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-select datagrid-fixed-column\"\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Single\"\n >\n <div class=\"clr-sr-only\">{{clrDgSingleSelectionAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for single row action; only displayType if we have at least one actionable row in datagrid -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-row-actions datagrid-fixed-column\"\n *ngIf=\"rowActionService.hasActionableRow\"\n >\n <div class=\"clr-sr-only\">{{clrDgSingleActionableAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for carets; only displayType if we have at least one expandable row in datagrid -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-expandable-caret datagrid-fixed-column\"\n *ngIf=\"expandableRows.hasExpandableRow || detailService.enabled\"\n >\n <div class=\"clr-sr-only\">{{clrDetailExpandableAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n </div>\n <div class=\"datagrid-row-scrollable\">\n <ng-container #projectedDisplayColumns></ng-container>\n </div>\n <div *ngIf=\"virtualScroll\" class=\"datagrid-row-sticky datagrid-row-sticky-scroll\">\n <div class=\"datagrid-column\"></div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"datagrid-content\" [class.datagrid-content-virtual]=\"virtualScroll\" #contentWrapper>\n <div\n *ngIf=\"virtualScroll\"\n class=\"datagrid-content-virtual-spacer\"\n [style.height]=\"virtualScroll?.totalContentHeight\"\n ></div>\n <div role=\"presentation\" #rowsWrapper class=\"datagrid-rows\">\n <clr-dg-row class=\"datagrid-row-loading\" *ngIf=\"loadingMoreItems\">\n <clr-dg-cell>\n <clr-spinner clrMedium></clr-spinner>\n <span>{{ commonStrings.keys.loading }}</span>\n </clr-dg-cell>\n </clr-dg-row>\n\n <ng-container #displayedRows></ng-container>\n\n <clr-dg-row class=\"datagrid-row-loading\" *ngIf=\"loadingMoreItems\">\n <clr-dg-cell>\n <clr-spinner clrMedium></clr-spinner>\n <span>{{ commonStrings.keys.loading }}</span>\n </clr-dg-cell>\n </clr-dg-row>\n\n <!-- Custom placeholder overrides the default empty one -->\n <ng-content select=\"clr-dg-placeholder\"></ng-content>\n <clr-dg-placeholder *ngIf=\"!placeholder\"></clr-dg-placeholder>\n </div>\n </div>\n </div>\n </div>\n </div>\n <ng-content select=\"clr-dg-footer\"></ng-content>\n <div class=\"datagrid-spinner\" *ngIf=\"loading\">\n <clr-spinner clrMedium>Loading</clr-spinner>\n </div>\n </div>\n <ng-content select=\"[clrIfDetail],clr-dg-detail\"></ng-content>\n</div>\n\n<div class=\"datagrid-calculation-table\">\n <div class=\"datagrid-calculation-header\">\n <ng-container #projectedCalculationColumns></ng-container>\n </div>\n <ng-container #calculationRows></ng-container>\n</div>\n\n<ng-template #fixedColumnTemplate>\n <div class=\"datagrid-column datagrid-fixed-column\"></div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i12.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i13.ClrLabel, selector: "label", inputs: ["id", "for"] }, { kind: "directive", type: i14.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i14.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i14.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i15.ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }, { kind: "component", type: i16.ClrDatagridCell, selector: "clr-dg-cell" }, { kind: "component", type: i17.ClrDatagridPlaceholder, selector: "clr-dg-placeholder" }, { kind: "component", type: i18.ClrDatagridRow, selector: "clr-dg-row", inputs: ["clrDgDetailDisabled", "clrDgDetailHidden", "clrDgSkeletonLoading", "clrDgItem", "clrDgSelectable", "clrDgSelected", "clrDgExpanded", "clrDgDetailOpenLabel", "clrDgDetailCloseLabel", "clrDgRowSelectionLabel"], outputs: ["clrDgSelectedChange", "clrDgExpandedChange"] }, { kind: "directive", type: i19.ClrDatagridSelectionCellDirective, selector: ".datagrid-select" }, { kind: "directive", type: i20.DatagridCellRenderer, selector: "clr-dg-cell" }, { kind: "directive", type: i21.DatagridRowRenderer, selector: "clr-dg-row" }, { kind: "directive", type: i22.ActionableOompaLoompa, selector: "clr-datagrid, clr-dg-row" }, { kind: "directive", type: i23.ExpandableOompaLoompa, selector: "clr-datagrid, clr-dg-row" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagrid, decorators: [{
type: Component,
args: [{ selector: 'clr-datagrid', providers: [
Selection,
Sort,
FiltersProvider,
Page,
Items,
DatagridRenderOrganizer,
RowActionService,
ExpandableRowsCount,
StateDebouncer,
DetailService,
StateProvider,
TableSizeService,
ColumnsService,
DisplayModeService,
KeyNavigationGridController,
], host: {
'[class.datagrid-host]': 'true',
'[class.datagrid-detail-open]': 'detailService.isOpen',
'[class.datagrid-virtual-scroll]': '!!virtualScroll',
}, template: "<!--\n ~ Copyright (c) 2016-2025 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<ng-content select=\"clr-dg-action-bar\"></ng-content>\n<div class=\"datagrid-outer-wrapper\">\n <div class=\"datagrid-inner-wrapper\">\n <div class=\"datagrid\" #datagrid [attr.aria-hidden]=\"detailService.isOpen ? true : null\">\n <div class=\"datagrid-table-wrapper\">\n <div role=\"grid\" class=\"datagrid-table\" tabindex=\"-1\" #datagridTable>\n <div role=\"rowgroup\" class=\"datagrid-header\" #datagridHeader>\n <div role=\"row\" class=\"datagrid-row\">\n <div class=\"datagrid-row-master datagrid-row-flex\">\n <div class=\"datagrid-row-sticky\">\n <!--header for datagrid where you can select multiple rows -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-select datagrid-fixed-column\"\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Multi\"\n (keydown.space)=\"toggleAllSelected($event)\"\n >\n <div *ngIf=\"!virtualScroll || customSelectAllEnabled\" class=\"clr-checkbox-wrapper\">\n <!-- We need to move focus and space-key handling to the parent because of keyboard arrow key navigation,\n which is not able to transfer focus directly on the input when focused with the tab key -->\n <input\n #selectAllCheckbox\n type=\"checkbox\"\n [id]=\"selectAllId\"\n [(ngModel)]=\"allSelected\"\n [attr.aria-label]=\"commonStrings.keys.selectAll\"\n tabindex=\"-1\"\n />\n <!-- Usage of class clr-col-null here prevents clr-col-* classes from being added when a datagrid is wrapped inside clrForm -->\n <label [for]=\"selectAllId\" class=\"clr-control-label clr-col-null\">\n <span class=\"clr-sr-only\">{{commonStrings.keys.selectAll}}</span>\n </label>\n </div>\n\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for datagrid where you can select one row only -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-select datagrid-fixed-column\"\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Single\"\n >\n <div class=\"clr-sr-only\">{{clrDgSingleSelectionAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for single row action; only displayType if we have at least one actionable row in datagrid -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-row-actions datagrid-fixed-column\"\n *ngIf=\"rowActionService.hasActionableRow\"\n >\n <div class=\"clr-sr-only\">{{clrDgSingleActionableAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n <!-- header for carets; only displayType if we have at least one expandable row in datagrid -->\n <div\n #stickyHeader\n role=\"columnheader\"\n class=\"datagrid-column datagrid-expandable-caret datagrid-fixed-column\"\n *ngIf=\"expandableRows.hasExpandableRow || detailService.enabled\"\n >\n <div class=\"clr-sr-only\">{{clrDetailExpandableAriaLabel}}</div>\n <div class=\"datagrid-column-separator\"></div>\n </div>\n </div>\n <div class=\"datagrid-row-scrollable\">\n <ng-container #projectedDisplayColumns></ng-container>\n </div>\n <div *ngIf=\"virtualScroll\" class=\"datagrid-row-sticky datagrid-row-sticky-scroll\">\n <div class=\"datagrid-column\"></div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"datagrid-content\" [class.datagrid-content-virtual]=\"virtualScroll\" #contentWrapper>\n <div\n *ngIf=\"virtualScroll\"\n class=\"datagrid-content-virtual-spacer\"\n [style.height]=\"virtualScroll?.totalContentHeight\"\n ></div>\n <div role=\"presentation\" #rowsWrapper class=\"datagrid-rows\">\n <clr-dg-row class=\"datagrid-row-loading\" *ngIf=\"loadingMoreItems\">\n <clr-dg-cell>\n <clr-spinner clrMedium></clr-spinner>\n <span>{{ commonStrings.keys.loading }}</span>\n </clr-dg-cell>\n </clr-dg-row>\n\n <ng-container #displayedRows></ng-container>\n\n <clr-dg-row class=\"datagrid-row-loading\" *ngIf=\"loadingMoreItems\">\n <clr-dg-cell>\n <clr-spinner clrMedium></clr-spinner>\n <span>{{ commonStrings.keys.loading }}</span>\n </clr-dg-cell>\n </clr-dg-row>\n\n <!-- Custom placeholder overrides the default empty one -->\n <ng-content select=\"clr-dg-placeholder\"></ng-content>\n <clr-dg-placeholder *ngIf=\"!placeholder\"></clr-dg-placeholder>\n </div>\n </div>\n </div>\n </div>\n </div>\n <ng-content select=\"clr-dg-footer\"></ng-content>\n <div class=\"datagrid-spinner\" *ngIf=\"loading\">\n <clr-spinner clrMedium>Loading</clr-spinner>\n </div>\n </div>\n <ng-content select=\"[clrIfDetail],clr-dg-detail\"></ng-content>\n</div>\n\n<div class=\"datagrid-calculation-table\">\n <div class=\"datagrid-calculation-header\">\n <ng-container #projectedCalculationColumns></ng-container>\n </div>\n <ng-container #calculationRows></ng-container>\n</div>\n\n<ng-template #fixedColumnTemplate>\n <div class=\"datagrid-column datagrid-fixed-column\"></div>\n</ng-template>\n" }]
}], ctorParameters: function () { return [{ type: i1.DatagridRenderOrganizer }, { type: i2.Items }, { type: i3.ExpandableRowsCount }, { type: i4.Selection }, { type: i5.RowActionService }, { type: i6.StateProvider }, { type: i7.DisplayModeService }, { type: i0.Renderer2 }, { type: i8.DetailService }, { type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }, { type: i0.ElementRef }, { type: i9.Page }, { type: i10.ClrCommonStringsService }, { type: i11.KeyNavigationGridController }, { type: i0.NgZone }]; }, propDecorators: { loadingMoreItems: [{
type: Input,
args: ['clrLoadingMoreItems']
}], clrDgSingleSelectionAriaLabel: [{
type: Input
}], clrDgSingleActionableAriaLabel: [{
type: Input
}], clrDetailExpandableAriaLabel: [{
type: Input
}], clrDgDisablePageFocus: [{
type: Input
}], selectedChanged: [{
type: Output,
args: ['clrDgSelectedChange']
}], singleSelectedChanged: [{
type: Output,
args: ['clrDgSingleSelectedChange']
}], refresh: [{
type: Output,
args: ['clrDgRefresh']
}], customSelectAllEnabled: [{
type: Input,
args: ['clrDgCustomSelectAllEnabled']
}], customSelectAll: [{
type: Output,
args: ['clrDgCustomSelectAll']
}], _virtualScroll: [{
type: ContentChildren,
args: [ClrDatagridVirtualScrollDirective]
}], iterator: [{
type: ContentChild,
args: [ClrDatagridItems]
}], placeholder: [{
type: ContentChild,
args: [ClrDatagridPlaceholder]
}], columns: [{
type: ContentChildren,
args: [ClrDatagridColumn]
}], rows: [{
type: ContentChildren,
args: [ClrDatagridRow, { emitDistinctChangesOnly: false }]
}], datagrid: [{
type: ViewChild,
args: ['datagrid', { read: ElementRef }]
}], datagridTable: [{
type: ViewChild,
args: ['datagridTable', { read: ElementRef }]
}], datagridHeader: [{
type: ViewChild,
args: ['datagridHeader', { read: ElementRef }]
}], contentWrapper: [{
type: ViewChild,
args: ['contentWrapper', { read: ElementRef, static: true }]
}], rowsWrapper: [{
type: ViewChild,
args: ['rowsWrapper', { read: ElementRef, static: true }]
}], scrollableColumns: [{
type: ViewChild,
args: ['scrollableColumns', { read: ViewContainerRef }]
}], _projectedDisplayColumns: [{
type: ViewChild,
args: ['projectedDisplayColumns', { read: ViewContainerRef }]
}], _projectedCalculationColumns: [{
type: ViewChild,
args: ['projectedCalculationColumns', { read: ViewContainerRef }]
}], _displayedRows: [{
type: ViewChild,
args: ['displayedRows', { read: ViewContainerRef }]
}], _calculationRows: [{
type: ViewChild,
args: ['calculationRows', { read: ViewContainerRef }]
}], _fixedColumnTemplate: [{
type: ViewChild,
args: ['fixedColumnTemplate']
}], stickyHeaders: [{
type: ViewChildren,
args: ['stickyHeader', { emitDistinctChangesOnly: true }]
}], selectAllCheckbox: [{
type: ViewChild,
args: ['selectAllCheckbox']
}], loading: [{
type: Input,
args: ['clrDgLoading']
}], selected: [{
type: Input,
args: ['clrDgSelected']
}], singleSelected: [{
type: Input,
args: ['clrDgSingleSelected']
}], clrDgPreserveSelection: [{
type: Input
}], rowSelectionMode: [{
type: Input,
args: ['clrDgRowSelection']
}], trackBy: [{
type: Input,
args: ['clrDgItemsTrackBy']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWdyaWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyL3NyYy9kYXRhL2RhdGFncmlkL2RhdGFncmlkLnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci9zcmMvZGF0YS9kYXRhZ3JpZC9kYXRhZ3JpZC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNDLE9BQU8sRUFHTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLGVBQWUsRUFFZixVQUFVLEVBQ1YsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBR0wsTUFBTSxFQUlOLFNBQVMsRUFDVCxZQUFZLEVBQ1osZ0JBQWdCLEdBQ2pCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHekQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLCtDQUErQyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsaUNBQWlDLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN4RixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFdkQs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