UNPKG

@clr/angular

Version:

Angular components for Clarity

556 lines 102 kB
/* * 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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