@WidgetComponent

nm-data-list-component

File

src/app/shared/widgets/data-list/data-list-component/data-list.component.ts

Implements

OnInit OnDestroy AfterViewInit

Metadata

providers EditAttributeService
selector nm-data-list-component
styleUrls data-list.component.scss
templateUrl ./data-list.component.html

Index

Widget inputs
Widget outputs
Properties
Methods
Inputs
Outputs

Constructor

constructor(localStorageService: LocalStorageService, dialog: DialogService, notificationService: CustomNotificationService, translateService: TranslateService, currentLocaleService: CurrentLocaleService, widgetFrameService: WidgetframeService, appContext: AppContext, appdataStore: AppdataStore, cdr: ChangeDetectorRef, http: HttpClient, progressbarService: ProgressbarService, editAttributeService: EditAttributeService, scrollService: ScrollService, dataListExportService: DataListExportService, websocketService: WebsocketService, userService: UserService, dataListEndEditService: DataListEndEditService, validationService: ValidationService, unsavedChangesService: UnsavedChangesService, appService: AppService, module: NmModuleDescriptor)
Parameters :
Name Type Optional
localStorageService LocalStorageService no
dialog DialogService no
notificationService CustomNotificationService no
translateService TranslateService no
currentLocaleService CurrentLocaleService no
widgetFrameService WidgetframeService no
appContext AppContext no
appdataStore AppdataStore no
cdr ChangeDetectorRef no
http HttpClient no
progressbarService ProgressbarService no
editAttributeService EditAttributeService no
scrollService ScrollService no
dataListExportService DataListExportService no
websocketService WebsocketService no
userService UserService no
dataListEndEditService DataListEndEditService no
validationService ValidationService no
unsavedChangesService UnsavedChangesService no
appService AppService no
module NmModuleDescriptor no

Inputs

additionalParams
attributeUrl
autoFocus

Type: boolean

Default value: false

clearCellSelection
clearFiltersAndSorting
clearRowSelection
configuration

Type: DataListConfiguration

contextIdentifier
data
dataTypeInput
dataTypeMode
disableCellEditMode
dynamicColumnsIn
eagerLimit
endGridEditMode
export
filterColumns
locale
preselectAttributeProfile
products
refreshRows
reload
reset
resetEditData
restoreGlobalFilter
rowSelection
shownAttributesIn
uri
widgetId

Type: string

Outputs

api $event type: EventEmitter
currentData $event type: EventEmitter
dataLoaded $event type: EventEmitter
dataType $event type: EventEmitter
dynamicColumns $event type: EventEmitter
dynamicPrefix $event type: EventEmitter
editableCell $event type: EventEmitter
editedRow $event type: EventEmitter
editedRows $event type: EventEmitter
gridOutput $event type: EventEmitter
isValid $event type: EventEmitter
onCellSelect $event type: EventEmitter
onDrop $event type: EventEmitter
reorderedRows $event type: EventEmitter
rowEditEnter $event type: EventEmitter
rowEditLeave $event type: EventEmitter
selectedItems $event type: EventEmitter
shownAttributes $event type: EventEmitter
statusOut $event type: EventEmitter
tileClicked $event type: EventEmitter
toggleButtonChange $event type: EventEmitter
total $event type: EventEmitter
viewMode $event type: EventEmitter

Methods

Public applyDensityFromLocalStorage
applyDensityFromLocalStorage()
Returns : void
Private applyExcelPasteData
applyExcelPasteData(response: , selectedCell: )
Parameters :
Name Optional
response no
selectedCell no
Returns : void
Private autosizeColumns
autosizeColumns()
Returns : void
Protected buildLazyAllSelectionEvent
buildLazyAllSelectionEvent(event: any, grid: IgxGridBaseDirective, service: DataListService)
Parameters :
Name Type Optional
event any no
grid IgxGridBaseDirective no
service DataListService no
Returns : SelectionParams
Protected buildSelectionEvent
buildSelectionEvent(event: any, grid: IgxGridComponent | IgxHierarchicalGridComponent | IgxTreeGridComponent, service: DataListService)
Parameters :
Name Type Optional
event any no
grid IgxGridComponent | IgxHierarchicalGridComponent | IgxTreeGridComponent no
service DataListService no
Returns : SelectionParams
calcTableHeight
calcTableHeight()
Returns : string
Private checkCellForErrors
checkCellForErrors(cell: ListCellEditComponent | ListCellComponent)
Parameters :
Name Type Optional
cell ListCellEditComponent | ListCellComponent no
Returns : boolean
Public clearAllFiltersAndSorting
clearAllFiltersAndSorting(clearGrouping: , loadData: boolean, restoreGlobalFilter: )
Parameters :
Name Type Optional Default value
clearGrouping no true
loadData boolean no true
restoreGlobalFilter no false
Returns : void
Public clearColumnFilter
clearColumnFilter(input: any, column: any)
Parameters :
Name Type Optional
input any no
column any no
Returns : void
Public clearGlobalFilter
clearGlobalFilter()
Returns : void
Protected clearSelectedRows
clearSelectedRows()
Returns : void
closeContextMenu
closeContextMenu()
Returns : void
columnInit
columnInit(column: any)
Parameters :
Name Type Optional
column any no
Returns : void
columnOrderChanged
columnOrderChanged(columnIdentifiers: string[])
Parameters :
Name Type Optional
columnIdentifiers string[] no
Returns : void
Protected dataLoaded
dataLoaded(data: )
Parameters :
Name Optional
data no
Returns : void
Public dataPasted
dataPasted(processedData: string[][])
Parameters :
Name Type Optional
processedData string[][] no
Returns : void
Private doInitialSorting
doInitialSorting()
Returns : void
Public doRefresh
doRefresh()
Returns : void
Public doReload
doReload(force: boolean)
Parameters :
Name Type Optional Default value
force boolean no false
Returns : void
Protected doReset
doReset()
Returns : void
Public editShownAttributes
editShownAttributes()
Returns : void
Private emitDataListStatus
emitDataListStatus(lastChange: string)
Parameters :
Name Type Optional
lastChange string no
Returns : void
Public fireEditedRowsEvent
fireEditedRowsEvent(rowId: string, gridRow: any, parent: string, attributes: , configuration: DataListConfiguration)
Parameters :
Name Type Optional
rowId string no
gridRow any no
parent string no
attributes no
configuration DataListConfiguration no
Returns : void
Public getCellClass
getCellClass(nmColumn: )
Parameters :
Name Optional
nmColumn no
Returns : any
Public getColumnHeaderClasses
getColumnHeaderClasses(column: Column)
Parameters :
Name Type Optional
column Column no
Returns : {}
Private getCurrentRowIndex
getCurrentRowIndex(rowList: , cursorPosition: )
Parameters :
Name Optional
rowList no
cursorPosition no
Returns : any
Public getDynamicPrefix
getDynamicPrefix()
Returns : string
Public getGridColumnWidth
getGridColumnWidth(column: Column)
Parameters :
Name Type Optional
column Column no
Returns : any
getHeaderClass
getHeaderClass(nmColumn: )
Parameters :
Name Optional
nmColumn no
Returns : any
Public getHighlightReadOnly
getHighlightReadOnly()
Returns : boolean
Protected getShownAttributes
getShownAttributes()
Returns : any
Private getSortDirection
getSortDirection(direction: )
Parameters :
Name Optional
direction no
Returns : any
getTableHeight
getTableHeight()
Returns : string
Public getTranslationKey
getTranslationKey(column: Column)
Parameters :
Name Type Optional
column Column no
Returns : any
Public groupingComparer
groupingComparer(column: Column)
Parameters :
Name Type Optional
column Column no
Returns : any
Protected handleInput
handleInput(link: )
Parameters :
Name Optional
link no
Returns : void
Public ngAfterViewInit
ngAfterViewInit()
Returns : void
Public ngOnDestroy
ngOnDestroy()
Returns : void
Public ngOnInit
ngOnInit()
Returns : void
onCellClick
onCellClick(event: )
Parameters :
Name Optional
event no
Returns : void
onCellEdit
onCellEdit(event: IGridEditEventArgs, configuration: DataListConfiguration)
Parameters :
Name Type Optional Default value
event IGridEditEventArgs no
configuration DataListConfiguration no this.configuration
Returns : void
onCellEditEnter
onCellEditEnter(event: IGridEditEventArgs)
Parameters :
Name Type Optional
event IGridEditEventArgs no
Returns : void
onCellEditExit
onCellEditExit()
Returns : void
Public onColumnFilterInput
onColumnFilterInput(input: any, column: IgxColumnComponent)
Parameters :
Name Type Optional
input any no
column IgxColumnComponent no
Returns : void
onDataColumnsChange
onDataColumnsChange(visibleDataColumns: string[], showAllColumns: boolean)
Parameters :
Name Type Optional Default value
visibleDataColumns string[] no
showAllColumns boolean no false
Returns : void
Public onDataTypeChange
onDataTypeChange(reload: boolean)
Parameters :
Name Type Optional Default value
reload boolean no true
Returns : void
Public onDrop
onDrop(event: )
Parameters :
Name Optional
event no
Returns : void
Public onExport
onExport(settings: )
Parameters :
Name Optional
settings no
Returns : void
onFilteringDone
onFilteringDone()
Returns : void
Public onFilterValueChange
onFilterValueChange()
Returns : void
onHeaderSelectorClick
onHeaderSelectorClick(event: any)
Parameters :
Name Type Optional
event any no
Returns : void
Protected onInput
onInput(link: )
Parameters :
Name Optional
link no
Returns : void
Public onItemDropped
onItemDropped(event: , cell: IgxGridCell, column: Column)
Parameters :
Name Type Optional
event no
cell IgxGridCell no
column Column no
Returns : void
onRangeSelection
onRangeSelection(event: GridSelectionRange)
Parameters :
Name Type Optional
event GridSelectionRange no
Returns : void
Public onRowDragStart
onRowDragStart(event: )
Parameters :
Name Optional
event no
Returns : any
Public onRowEdit
onRowEdit(event: IGridEditEventArgs, configuration: DataListConfiguration, parent: string)
Parameters :
Name Type Optional Default value
event IGridEditEventArgs no
configuration DataListConfiguration no this.configuration
parent string no null
Returns : void
Public onRowEditCancel
onRowEditCancel()
Returns : void
Public onRowEditEnter
onRowEditEnter()
Returns : void
Public onRowSelection
onRowSelection(event: any)
Parameters :
Name Type Optional
event any no
Returns : void
onViewModeChange
onViewModeChange()
Returns : void
Public onVisibilityChanged
onVisibilityChanged(event: )
Parameters :
Name Optional
event no
Returns : void
Public openContextmenu
openContextmenu(eventArgs: )
Parameters :
Name Optional
eventArgs no
Returns : void
Public openDialogForShownAttributes
openDialogForShownAttributes()
Returns : void
Private prepareExcelPasteRequestData
prepareExcelPasteRequestData(selectedCell: , processedData: string[][])
Parameters :
Name Type Optional
selectedCell no
processedData string[][] no
Public primaryKey
primaryKey(configuration: DataListTreeConfiguration)
Parameters :
Name Type Optional
configuration DataListTreeConfiguration no
Returns : string
processDataOnChange
processDataOnChange(event: , reset: boolean)
Parameters :
Name Type Optional
event no
reset boolean no
Returns : void
Public reRender
reRender(ids: string[])
Parameters :
Name Type Optional
ids string[] no
Returns : void
selectAvailableRows
selectAvailableRows(result: SelectionParams, grid: IgxGridBaseDirective, service: DataListService, rowData: any[])
Parameters :
Name Type Optional
result SelectionParams no
grid IgxGridBaseDirective no
service DataListService no
rowData any[] no
Returns : any
Private setDefaultGroupingExpression
setDefaultGroupingExpression()
Returns : void
Private setDefaultSortingExpressions
setDefaultSortingExpressions()
Returns : void
Protected setDynamicColumns
setDynamicColumns(attributes: )
Parameters :
Name Optional
attributes no
Returns : void
Protected setEditedRowsData
setEditedRowsData(rowId: string, row: any, parent: string, attributes: , configuration: DataListConfiguration)
Parameters :
Name Type Optional
rowId string no
row any no
parent string no
attributes no
configuration DataListConfiguration no
Returns : void
Public setStaticHeight
setStaticHeight(newrows: number)
Parameters :
Name Type Optional Default value
newrows number no 0
Returns : void
Public showFilteringRow
showFilteringRow(event: )
Parameters :
Name Optional
event no
Returns : void
Public sortStrategy
sortStrategy(column: Column)
Parameters :
Name Type Optional
column Column no
Returns : ISortingStrategy
Public stopPropagation
stopPropagation(event: , field: )
Parameters :
Name Optional
event no
field no
Returns : boolean
Protected subscribeToInputs
subscribeToInputs()
Returns : void
Public takeRecommendedAttributes
takeRecommendedAttributes(recommendedAttributes: RecommendedAttributes)
Parameters :
Name Type Optional
recommendedAttributes RecommendedAttributes no
Returns : boolean
Public tileClicked
tileClicked(event: )
Parameters :
Name Optional
event no
Returns : void
Public toggleMode
toggleMode(event: )
Parameters :
Name Optional
event no
Returns : void
Public trackColumns
trackColumns(index: number, column: Column)
Parameters :
Name Type Optional
index number no
column Column no
Returns : string
Protected updateDataLocale
updateDataLocale(locale: )
Parameters :
Name Optional
locale no
Returns : void
updateDataOutput
updateDataOutput()
Returns : void
Public updateDynamicColumns
updateDynamicColumns(attributes: )

Function that gets called everytime the columns get updated from the SelectAttributesDialogComponent. Will directly call setDynamicColumns, if not overwritten

Parameters :
Name Optional
attributes no
Returns : void
Protected updateLocale
updateLocale(locale: )
Parameters :
Name Optional
locale no
Returns : void
Private updateTranslations
updateTranslations(transObj?: LangChangeEvent)
Parameters :
Name Type Optional
transObj LangChangeEvent yes
Returns : void
Protected validateAllRows
validateAllRows()
Returns : boolean
Protected validateGrid
validateGrid(grid: IgxGridBaseDirective)
Parameters :
Name Type Optional
grid IgxGridBaseDirective no
Returns : boolean
Public validateList
validateList(validation: any, configuration: DataListConfiguration)
Parameters :
Name Type Optional
validation any no
configuration DataListConfiguration no
Returns : void

Properties

Public _primaryKey
_primaryKey: string
Type : string
Private ALWAYS_ALLOWED_TYPES
ALWAYS_ALLOWED_TYPES: []
Type : []
Default value : [ "LOCALIZED_STRING", "PLAIN_STRING", "INTEGER_NUMBER", "DECIMAL_NUMBER", "DATE", ]
Public attributesDataType
attributesDataType: string
Type : string
Public attributeUrl
attributeUrl: string
Type : string
Public attributeUrlChannel
attributeUrlChannel:
Default value : new Subject<string>()
Public attributeUrlParams
attributeUrlParams: any
Type : any
Default value : {}
Public availableDataTypes
availableDataTypes: any[]
Type : any[]
Default value : []
Public cellEditModeActive
cellEditModeActive: boolean
Type : boolean
Default value : false
Private cellSelectable
cellSelectable: boolean
Type : boolean
childComponentMenu
childComponentMenu: DataListContextMenuComponent
Type : DataListContextMenuComponent
Decorators : ViewChild
Private clearCellSelectionChannel
clearCellSelectionChannel:
Default value : new Subject<void>()
Private clearFiltersAndSortingChannel
clearFiltersAndSortingChannel:
Default value : new Subject<void>()
Private clearRowSelectionChannel
clearRowSelectionChannel:
Default value : new Subject<void>()
Private clearSortingAndFilteringOnReset
clearSortingAndFilteringOnReset: boolean
Type : boolean
Public clipboardOptions
clipboardOptions: any
Type : any
Public columns
columns: DataListColumnsService
Type : DataListColumnsService
Public columnSelector
columnSelector: ColumnSelectorCallback
Type : ColumnSelectorCallback
Public contentVisible
contentVisible: boolean
Type : boolean
Default value : true
Public contextContent
contextContent:
Public contextIdentifierChannel
contextIdentifierChannel:
Default value : new ReplaySubject<any>(1)
Public contextMenuColumn
contextMenuColumn: Column
Type : Column
Public contextMenuCoordinates
contextMenuCoordinates: any
Type : any
Default value : { x: 50, y: 50, }
Public contextValue
contextValue:
Public currentDataChannel
currentDataChannel:
Default value : new ReplaySubject<any>(1)
Public currentLocaleService
currentLocaleService: CurrentLocaleService
Type : CurrentLocaleService
Private customFilter
customFilter:
Default value : CustomFilteringOperand.instance()
Private dataChannel
dataChannel:
Default value : new ReplaySubject<any>(1)
Protected dataInitialized
dataInitialized: boolean
Type : boolean
Default value : false
dataListStateDirective
dataListStateDirective: DataListStateDirective
Type : DataListStateDirective
Decorators : ViewChild
Public dataType
dataType:
Public dataTypeInputChannel
dataTypeInputChannel:
Default value : new Subject<any>()
Public dataTypeModeChannel
dataTypeModeChannel:
Default value : new BehaviorSubject<string>("choose")
Public density
density: DisplayDensity
Type : DisplayDensity
Default value : DisplayDensity.compact
Private disableCellEditModeChannel
disableCellEditModeChannel:
Default value : new Subject<void>()
Private disableContextMenu
disableContextMenu: boolean
Type : boolean
Public dynamicColumnsInSubject
dynamicColumnsInSubject:
Default value : new Subject<any[]>()
Public eagerLimitChannel
eagerLimitChannel: ReplaySubject<number>
Type : ReplaySubject<number>
Default value : new ReplaySubject<number>( 1 )
editableListCells
editableListCells: QueryList<ListCellEditComponent>
Type : QueryList<ListCellEditComponent>
Decorators : ViewChildren
Protected editedRows
editedRows: DataListEditedRows
Type : DataListEditedRows
Default value : {}
Private endGridEditChannel
endGridEditChannel:
Default value : new Subject<void>()
Private exportChannel
exportChannel:
Default value : new Subject<any>()
Public filterColumnsChannel
filterColumnsChannel:
Default value : new Subject<any>()
Public filterMode
filterMode: string
Type : string
Public frameHeight
frameHeight: number
Type : number
Default value : DEFAULT_FRAME_HEIGHT_PX
Private getNextPageOnLazyLoad
getNextPageOnLazyLoad: boolean
Type : boolean
Public globalFilterInput
globalFilterInput: boolean
Type : boolean
Public globalFilterValue
globalFilterValue: string
Type : string
Public grid
grid: IgxGridComponent
Type : IgxGridComponent
Decorators : ViewChild
Public groupingEnabled
groupingEnabled: boolean
Type : boolean
Public groupingExpressions
groupingExpressions: IGroupingExpression[]
Type : IGroupingExpression[]
Default value : []
Public groupRowTemplate
groupRowTemplate: TemplateRef<any>
Type : TemplateRef<any>
Decorators : ViewChild
Public heightModifier
heightModifier: number
Type : number
Default value : 0
Public hideFilters
hideFilters: boolean
Type : boolean
Default value : false
Public identifierCol
identifierCol:
Public infoText
infoText: string
Type : string
Default value : "list.results"
Public initialDataType
initialDataType: string
Type : string
inputBoxes
inputBoxes: QueryList<ElementRef>
Type : QueryList<ElementRef>
Decorators : ViewChildren
Private inputChannel
inputChannel: ReplaySubject<any>
Type : ReplaySubject<any>
Default value : new ReplaySubject<any>(1)
Public isEagerLoading
isEagerLoading: boolean
Type : boolean
Default value : true
Public isListMode
isListMode: boolean
Type : boolean
Default value : true
Public lastSelectedCells
lastSelectedCells: GridSelectionRange
Type : GridSelectionRange
Private lastUriLocalStorage
lastUriLocalStorage: LocalStorageEntry
Type : LocalStorageEntry
listCells
listCells: QueryList<ListCellComponent>
Type : QueryList<ListCellComponent>
Decorators : ViewChildren
Public listService
listService: DataListService
Type : DataListService
Private localeChannel
localeChannel:
Default value : new BehaviorSubject<any>(null)
Private localstorageColumnsEntry
localstorageColumnsEntry: LocalStorageEntry
Type : LocalStorageEntry
Private localstorageShownAttributesEntry
localstorageShownAttributesEntry: LocalStorageEntry
Type : LocalStorageEntry
menuTrigger
menuTrigger: MatMenuTrigger
Type : MatMenuTrigger
Decorators : ViewChild
Public noopFilterStrategy
noopFilterStrategy:
Default value : NoopFilteringStrategy.instance()
Public noopSortStrategy
noopSortStrategy:
Default value : NoopSortingStrategy.instance()
Public outlet
outlet: IgxOverlayOutletDirective
Type : IgxOverlayOutletDirective
Decorators : ViewChild
Public overrideTileClickEvent
overrideTileClickEvent: boolean
Type : boolean
Private pageLimitPerScroll
pageLimitPerScroll: number
Type : number
Public pinningConfig
pinningConfig: IPinningConfig
Type : IPinningConfig
Default value : { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Top, }
Private preselectAttributeProfile
preselectAttributeProfile: string
Type : string
Private preselectAttributeProfileChannel
preselectAttributeProfileChannel:
Default value : new Subject<string>()
Public productChannel
productChannel:
Default value : new Subject<string[]>()
Public refreshRows
refreshRows:
Default value : new Subject<any[]>()
Private reloadChannel
reloadChannel: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Public reloadOnDataTypeChange
reloadOnDataTypeChange: boolean
Type : boolean
Public removeColumnHeader
removeColumnHeader: boolean
Type : boolean
Public resetChannel
resetChannel:
Default value : new Subject<any>()
Private resetEditDataChannel
resetEditDataChannel:
Default value : new Subject<void>()
Public restoreGlobalFilter
restoreGlobalFilter:
Default value : new BehaviorSubject<boolean>(false)
Public rowPinningEnabled
rowPinningEnabled: boolean
Type : boolean
Default value : false
Public rowSelectable
rowSelectable: boolean
Type : boolean
Private rowSelectionChannel
rowSelectionChannel:
Default value : new Subject<any>()
Public rowSelectionMode
rowSelectionMode: string
Type : string
Public rowSelectionType
rowSelectionType: string
Type : string
Default value : "multiple"
Public selectAllCheckbox
selectAllCheckbox: boolean
Type : boolean
Default value : false
Public selectedDataType
selectedDataType: string
Type : string
Private selectedDataTypeStorage
selectedDataTypeStorage: LocalStorageEntry
Type : LocalStorageEntry
Public selectedViewMode
selectedViewMode:
Public selectOptions
selectOptions:
Public selectOptionsUriChannel
selectOptionsUriChannel: ReplaySubject<any>
Type : ReplaySubject<any>
Default value : new ReplaySubject<any>( 1 )
Public showActionsInTableColumn
showActionsInTableColumn: boolean
Type : boolean
Default value : false
Public showAllColumns
showAllColumns: boolean
Type : boolean
Default value : true
Public showFilterRow
showFilterRow: boolean
Type : boolean
Default value : false
Private shownAttributesInputChannel
shownAttributesInputChannel:
Default value : new ReplaySubject<any>(1)
Public slideChange
slideChange:
Default value : new Subject<number>()
Public slidevalue
slidevalue: number
Type : number
Default value : 3
Private sortBy
sortBy: SortBy[]
Type : SortBy[]
Public sortingExpressions
sortingExpressions: ISortingExpression[]
Type : ISortingExpression[]
Default value : []
Public storingEnabled
storingEnabled: boolean
Type : boolean
Default value : false
Public tableGridHeight
tableGridHeight: string
Type : string
Public tableGridWidth
tableGridWidth: string
Type : string
Public tableHeight
tableHeight: string
Type : string
Private tableHeightRelativeToRows
tableHeightRelativeToRows: boolean
Type : boolean
Private tableHeightVisibleRows
tableHeightVisibleRows: number
Type : number
Public tableWidth
tableWidth: null
Type : null
Default value : null
Public tileIdentifierField
tileIdentifierField: string
Type : string
Public tileRedirectLink
tileRedirectLink: string
Type : string
Public toggleButtonLabel
toggleButtonLabel: string
Type : string
Public total
total:
unsubscribe
unsubscribe:
Default value : NgUnsubscribe.create()
Private viewModeLocalStorage
viewModeLocalStorage: LocalStorageEntry
Type : LocalStorageEntry
Public viewModeOptions
viewModeOptions:
Public viewPortHeight
viewPortHeight: number
Type : number
Default value : window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
Public visibleDataColumns
visibleDataColumns: string[]
Type : string[]
Public visibleDataColumnsOptions
visibleDataColumnsOptions: Observable<Column[]>
Type : Observable<Column[]>
Public visibleDataColumnsStorage
visibleDataColumnsStorage: LocalStorageEntry
Type : LocalStorageEntry
Public widgetSortingStrategy
widgetSortingStrategy:
Default value : new WidgetSortingStrategy()
Public wikiLink
wikiLink: string
Type : string

Accessors

uri
seturi(value: )
Parameters :
Name Optional
value no
Returns : void
resetEditData
setresetEditData(value: )
Parameters :
Name Optional
value no
Returns : void
locale
setlocale(value: )
Parameters :
Name Optional
value no
Returns : void
reload
setreload(value: )
Parameters :
Name Optional
value no
Returns : void
reset
setreset(value: )
Parameters :
Name Optional
value no
Returns : void
dataTypeMode
setdataTypeMode(value: )
Parameters :
Name Optional
value no
Returns : void
data
setdata(data: )
Parameters :
Name Optional
data no
Returns : void
contextIdentifier
setcontextIdentifier(data: )
Parameters :
Name Optional
data no
Returns : void
shownAttributes
setshownAttributes(data: )
Parameters :
Name Optional
data no
Returns : void
export
setexport(settings: )
Parameters :
Name Optional
settings no
Returns : void
disableCellEditMode
setdisableCellEditMode(value: )
Parameters :
Name Optional
value no
Returns : void
clearCellSelection
setclearCellSelection(value: )
Parameters :
Name Optional
value no
Returns : void
rowSelection
setrowSelection(value: )
Parameters :
Name Optional
value no
Returns : void
clearRowSelection
setclearRowSelection(value: )
Parameters :
Name Optional
value no
Returns : void
endGridEditMode
setendGridEditMode(value: )
Parameters :
Name Optional
value no
Returns : void
clearFiltersAndSorting
setclearFiltersAndSorting(value: )
Parameters :
Name Optional
value no
Returns : void
dataTypeInput
setdataTypeInput(value: )
Parameters :
Name Optional
value no
Returns : void
eagerLimit
seteagerLimit(value: )
Parameters :
Name Optional
value no
Returns : void
attributeUrlChannelInput
setattributeUrlChannelInput(value: )
Parameters :
Name Optional
value no
Returns : void
products
setproducts(value: )
Parameters :
Name Optional
value no
Returns : void
refreshRowInput
setrefreshRowInput(value: )
Parameters :
Name Optional
value no
Returns : void
restoreGlobalFilterInput
setrestoreGlobalFilterInput(value: )
Parameters :
Name Optional
value no
Returns : void
dynamicColumnsIn
setdynamicColumnsIn(value: )
Parameters :
Name Optional
value no
Returns : void
additionalParams
setadditionalParams(value: )
Parameters :
Name Optional
value no
Returns : void
filterColumns
setfilterColumns(value: )
Parameters :
Name Optional
value no
Returns : void
preselectAttributeProfileIn
setpreselectAttributeProfileIn(value: )
Parameters :
Name Optional
value no
Returns : void
import {
  AfterViewInit,
  ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  Inject,
  Input,
  OnDestroy,
  OnInit,
  Optional,
  Output,
  QueryList,
  TemplateRef,
  ViewChild,
  ViewChildren,
} from "@angular/core";
import {
  ColumnPinningPosition,
  DefaultSortingStrategy,
  FilteringLogic,
  GridSelectionRange,
  IGridEditEventArgs,
  IGroupingExpression,
  IgxColumnComponent,
  IgxGridBaseDirective,
  IgxGridCell,
  IgxGridComponent,
  IgxOverlayOutletDirective,
  IgxStringFilteringOperand,
  IPinningConfig,
  ISortingExpression,
  ISortingStrategy,
  RowPinningPosition,
  SortingDirection,
  IFilteringOperation,
  NoopFilteringStrategy,
  NoopSortingStrategy,
  IgxHierarchicalGridComponent,
  IgxTreeGridComponent,
  DisplayDensity,
} from "@infragistics/igniteui-angular";
import { HttpClient } from "@angular/common/http";
import { BehaviorSubject, Observable, ReplaySubject, Subject } from "rxjs";
import { getOrDefault, throwIfUndefined } from "../../widget.configuration";
import { NgUnsubscribe } from "../../../ng-unsubscribe";
import { debounceTime, filter, first, take, takeUntil } from "rxjs/operators";
import {
  LocalStorageEntry,
  LocalStorageService,
} from "../../../components/local-storage/local-storage.service";
import {
  DeletionMode,
  Scope,
} from "../../../components/local-storage/local-storage-constants";
import { DataListService } from "../data-list.service";
import { SelectAttributesDialogComponent } from "../../../components/dialog/selectAttributesDialog.component";
import { MatMenuTrigger } from "@angular/material/menu";
import {
  angularWidgetBridgeInput,
  deepCopy,
  flatCopy,
  getBodyStyleCssProperty,
} from "../../../components/util/util.service";
import { CurrentLocaleService } from "../../../components/i18n/currentLocale.service";
import { LangChangeEvent, TranslateService } from "@ngx-translate/core";
import { WidgetframeService } from "../../widgetframe/widgetframe.service";
import { AppContext } from "../../../components/app-context/app.context";
import { AppdataStore } from "../../../components/appdata/appdata.store";
import {
  Column,
  ColumnMap,
  DataListConfiguration,
  DataListStatus,
  DataListTreeConfiguration,
  RecommendedAttributes,
  SelectionParams,
  SortBy,
} from "../../interfaces/list.interfaces";
import { ProgressbarService } from "../../../components/progressbar/progressbar.service";
import { DataListColumnsService } from "../data-list-columns.service";
import { EditAttributeService } from "../../../components/edit-attribute/edit-attribute.service";
import { DataListContextMenuComponent } from "../data-list-context-menu-component/data-list-context-menu.component";
import { DataListStateDirective } from "../data-list-state.directive";
import { ScrollService } from "../../../components/scroll/scroll.service";
import { DataListExportService } from "../data-list-export.service";
import { CustomNotificationService } from "../../../components/notification/customnotification.service";
import { ListCellEditComponent } from "../../../components/list-cell/list-cell-edit.component";
import { ListCellComponent } from "../../../components/list-cell/list-cell.component";
import { densityStorageConfig } from "../../layoutcontainer/layoutcontainer.component";
import { AppService } from "../../configuration/app.service";
import { ConfirmationDialogComponent } from "../../../components/dialog/confirmationDialog.component";
import { WebsocketService } from "../../../components/services/websocket.service";
import { UserService } from "../../../components/user/user.service";
import { DataListApi, DataListApiImpl } from "../data-list.api";
import {
  Attribute,
  Attributes,
} from "../../../components/edit-attribute/attribute";
import {
  CellClassesCallbackRegistry,
  ColumnSelectorCallback,
  ColumnSelectorCallbackRegistry,
  HeaderClassesCallbackRegistry,
} from "../../configuration";
import {
  extractAttributeFromCell,
  extractAttributeFromRow,
} from "../../../components/list-cell/attribute.util";
import { DataListEndEditService } from "../data-list-end-edit.service";
import { ValidationService } from "../../../components/validation";
import {
  DataListActionParameter,
  updateRowOrCell,
} from "../default-footer-component/default-data-list-footer.component";
import { DialogService, PageDialogComponent } from "../../../components/dialog";
import { ResizeObserver } from "@juggle/resize-observer";
import {
  UnsavedChangesDialogConfiguration,
  UnsavedChangesService,
} from "../../../components/util";
import {
  NmModuleDescriptor,
  NOVOMIND_MODULE_DESCRIPTOR,
} from "../../../../nm.module-descriptor";
import { UtilService } from "../../../components/util/util.service";

const DEFAULT_FRAME_HEIGHT_PX: number = 270;

const DEFAULT_MODIFIERS: string[] = [
  "page-title",
  "page-frame",
  "data-list-frame",
  "data-list-header",
  "data-list-title",
  "data-list-column-header",
];
const TABLE_FOOTER_MODIFIER: string = "data-list-footer";
const DEFAULT_EDIT_BAR_HEIGHT_PX: number = 26;
export const DEFAULT_CLIPBOARD_OPTIONS = {
  enabled: true,
  copyHeaders: false,
  copyFormatters: false,
  separator: "\t",
};
const UNSAVED_CHANGES_DIALOG_CONFIG: UnsavedChangesDialogConfiguration = {
  allowCancel: false,
  allowExitWithoutSaving: true,
  allowSaveAndExit: true,
};

@Component({
  selector: "nm-data-list-component",
  templateUrl: "./data-list.component.html",
  styleUrls: ["./data-list.component.scss"],
  providers: [EditAttributeService],
})
export class DataListComponent implements OnInit, OnDestroy, AfterViewInit {
  @Input()
  public configuration: DataListConfiguration;
  public tileIdentifierField: string;

  @Input()
  public widgetId: string;

  @Input("uri")
  public set uri(value) {
    angularWidgetBridgeInput(value, this.inputChannel, this.unsubscribe);
  }

  @Input("resetEditData")
  public set resetEditData(value) {
    angularWidgetBridgeInput(
      value,
      this.resetEditDataChannel,
      this.unsubscribe
    );
  }

  @Input("locale")
  public set locale(value) {
    angularWidgetBridgeInput(value, this.localeChannel, this.unsubscribe);
  }

  @Input("reload")
  public set reload(value) {
    angularWidgetBridgeInput(value, this.reloadChannel, this.unsubscribe);
  }

  @Input("reset")
  public set reset(value) {
    angularWidgetBridgeInput(value, this.resetChannel, this.unsubscribe);
  }

  @Input("dataTypeMode")
  public set dataTypeMode(value) {
    angularWidgetBridgeInput(value, this.dataTypeModeChannel, this.unsubscribe);
  }

  @Input("data")
  public set data(data) {
    angularWidgetBridgeInput(data, this.dataChannel, this.unsubscribe);
  }

  @Input("contextIdentifier")
  public set contextIdentifier(data) {
    angularWidgetBridgeInput(
      data,
      this.contextIdentifierChannel,
      this.unsubscribe
    );
  }

  @Input("shownAttributesIn")
  public set shownAttributes(data) {
    angularWidgetBridgeInput(
      data,
      this.shownAttributesInputChannel,
      this.unsubscribe
    );
  }

  @Input("export")
  public set export(settings) {
    angularWidgetBridgeInput(settings, this.exportChannel, this.unsubscribe);
  }

  @Input("disableCellEditMode")
  public set disableCellEditMode(value) {
    angularWidgetBridgeInput(
      value,
      this.disableCellEditModeChannel,
      this.unsubscribe
    );
  }

  @Input("clearCellSelection")
  public set clearCellSelection(value) {
    angularWidgetBridgeInput(
      value,
      this.clearCellSelectionChannel,
      this.unsubscribe
    );
  }

  @Input("rowSelection")
  public set rowSelection(value) {
    angularWidgetBridgeInput(value, this.rowSelectionChannel, this.unsubscribe);
  }

  @Input("clearRowSelection")
  public set clearRowSelection(value) {
    angularWidgetBridgeInput(
      value,
      this.clearRowSelectionChannel,
      this.unsubscribe
    );
  }

  @Input("endGridEditMode")
  public set endGridEditMode(value) {
    angularWidgetBridgeInput(value, this.endGridEditChannel, this.unsubscribe);
  }

  @Input("clearFiltersAndSorting")
  public set clearFiltersAndSorting(value) {
    angularWidgetBridgeInput(
      value,
      this.clearFiltersAndSortingChannel,
      this.unsubscribe
    );
  }

  @Input("dataTypeInput")
  public set dataTypeInput(value) {
    angularWidgetBridgeInput(
      value,
      this.dataTypeInputChannel,
      this.unsubscribe
    );
  }

  @Input("eagerLimit")
  public set eagerLimit(value) {
    angularWidgetBridgeInput(value, this.eagerLimitChannel, this.unsubscribe);
  }

  @Input("attributeUrl")
  public set attributeUrlChannelInput(value) {
    angularWidgetBridgeInput(value, this.attributeUrlChannel, this.unsubscribe);
  }

  @Input("products")
  public set products(value) {
    angularWidgetBridgeInput(value, this.productChannel, this.unsubscribe);
  }

  @Input("refreshRows")
  public set refreshRowInput(value) {
    angularWidgetBridgeInput(value, this.refreshRows, this.unsubscribe);
  }

  @Input("restoreGlobalFilter")
  public set restoreGlobalFilterInput(value) {
    angularWidgetBridgeInput(value, this.restoreGlobalFilter, this.unsubscribe);
  }

  @Input("dynamicColumnsIn")
  public set dynamicColumnsIn(value) {
    angularWidgetBridgeInput(
      value,
      this.dynamicColumnsInSubject,
      this.unsubscribe
    );
  }

  @Input("additionalParams")
  public set additionalParams(value) {
    this.attributeUrlParams = value;
  }

  @Input("filterColumns")
  public set filterColumns(value) {
    angularWidgetBridgeInput(
      value,
      this.filterColumnsChannel,
      this.unsubscribe
    );
  }

  @Input("preselectAttributeProfile")
  public set preselectAttributeProfileIn(value) {
    angularWidgetBridgeInput(
      value,
      this.preselectAttributeProfileChannel,
      this.unsubscribe
    );
  }

  @Input("autoFocus") public autoFocus: boolean = false;

  @Output("dynamicPrefix")
  public dynamicPrefixOutput = new EventEmitter<string>();

  @Output("dynamicColumns")
  public dynamicColumnsOutput = new EventEmitter<Column[]>();

  @Output("selectedItems")
  public selectedItems = new EventEmitter<SelectionParams>();

  @Output("shownAttributes")
  public shownAttributesOutput = new EventEmitter<any[]>();

  @Output("editedRows")
  public editedRowsOutput = new EventEmitter<DataListEditedRows>();

  @Output("editedRow")
  public editedRowOutput = new EventEmitter<DataListEditedRow>();

  @Output("total")
  public totalOutput = new EventEmitter<any>();

  @Output("gridOutput")
  public gridOutput = new EventEmitter<any>();

  @Output("viewMode")
  public viewModeOutput = new EventEmitter<any>();

  @Output("dataType")
  public dataTypeOutput = new EventEmitter<any>();

  @Output("isValid")
  public isValidOutput = new EventEmitter<any>();

  @Output("dataLoaded")
  public dataLoadedOutput = new EventEmitter<any>();

  @Output("currentData")
  public currentData = new EventEmitter<any>();

  @Output("editableCell")
  public editableCell = new EventEmitter<any>();

  @Output("rowEditEnter")
  public rowEditEnterEmitter = new EventEmitter<any>();

  @Output("rowEditLeave")
  public rowEditLeaveEmitter = new EventEmitter<any>();

  @Output("api")
  public apiEmitter = new EventEmitter<DataListApi>();

  @Output("toggleButtonChange")
  public toggleButtonChangeEmitter = new EventEmitter<boolean>();

  @Output("tileClicked")
  public tileClickedEventEmitter = new EventEmitter<any>();

  @Output("statusOut")
  public statusOutput = new EventEmitter<DataListStatus>();

  @Output("reorderedRows")
  public reorderedRows = new EventEmitter<any>();

  @Output("onDrop")
  public onDropEmitter = new EventEmitter<any>();

  @Output("onCellSelect")
  public onCellSelect = new EventEmitter<any>();

  public attributeUrlChannel = new Subject<string>();
  public productChannel = new Subject<string[]>();
  public refreshRows = new Subject<any[]>();
  public dynamicColumnsInSubject = new Subject<any[]>();
  private resetEditDataChannel = new Subject<void>();
  private inputChannel: ReplaySubject<any> = new ReplaySubject<any>(1);
  private reloadChannel: Subject<any> = new Subject<any>();
  private localeChannel = new BehaviorSubject<any>(null);
  private dataChannel = new ReplaySubject<any>(1);
  private shownAttributesInputChannel = new ReplaySubject<any>(1);
  private exportChannel = new Subject<any>();
  public resetChannel = new Subject<any>();
  public currentDataChannel = new ReplaySubject<any>(1);
  public filterColumnsChannel = new Subject<any>();
  public contextIdentifierChannel = new ReplaySubject<any>(1);
  public restoreGlobalFilter = new BehaviorSubject<boolean>(false);
  private disableCellEditModeChannel = new Subject<void>();
  private clearCellSelectionChannel = new Subject<void>();
  private clearRowSelectionChannel = new Subject<void>();
  private rowSelectionChannel = new Subject<any>();
  private endGridEditChannel = new Subject<void>();
  private clearFiltersAndSortingChannel = new Subject<void>();
  private preselectAttributeProfileChannel = new Subject<string>();

  private preselectAttributeProfile: string;
  public tableWidth = null;
  public slidevalue: number = 3;
  public slideChange = new Subject<number>();

  public attributeUrl: string;
  public attributeUrlParams: any = {};
  public attributesDataType: string;

  public cellEditModeActive: boolean = false;

  // The column that was right clicked when opening the context menu
  public contextMenuColumn: Column;

  public dataTypeModeChannel = new BehaviorSubject<string>("choose");
  public dataTypeInputChannel = new Subject<any>();
  public groupingExpressions: IGroupingExpression[] = [];
  public sortingExpressions: ISortingExpression[] = [];
  public filterMode: string;
  public selectOptionsUriChannel: ReplaySubject<any> = new ReplaySubject<any>(
    1
  );
  public eagerLimitChannel: ReplaySubject<number> = new ReplaySubject<number>(
    1
  );

  @ViewChild("table", { static: true }) public grid: IgxGridComponent;
  @ViewChild("groupRowTemplate", { static: true })
  public groupRowTemplate: TemplateRef<any>;
  @ViewChild(MatMenuTrigger) menuTrigger: MatMenuTrigger;
  @ViewChild(DataListContextMenuComponent, { static: true })
  childComponentMenu: DataListContextMenuComponent;
  @ViewChild(DataListStateDirective)
  dataListStateDirective: DataListStateDirective;
  @ViewChildren(ListCellEditComponent)
  editableListCells: QueryList<ListCellEditComponent>;
  @ViewChildren(ListCellComponent) listCells: QueryList<ListCellComponent>;
  @ViewChildren("inputBox") inputBoxes: QueryList<ElementRef>;

  @ViewChild(IgxOverlayOutletDirective, {
    read: IgxOverlayOutletDirective,
    static: true,
  })
  public outlet: IgxOverlayOutletDirective;

  public pinningConfig: IPinningConfig = {
    columns: ColumnPinningPosition.Start,
    rows: RowPinningPosition.Top,
  };

  public isListMode: boolean = true;
  private lastUriLocalStorage: LocalStorageEntry;
  private localstorageShownAttributesEntry: LocalStorageEntry;
  private localstorageColumnsEntry: LocalStorageEntry;

  private viewModeLocalStorage: LocalStorageEntry;
  private selectedDataTypeStorage: LocalStorageEntry;

  public visibleDataColumns: string[];
  public visibleDataColumnsStorage: LocalStorageEntry;
  public visibleDataColumnsOptions: Observable<Column[]>;

  unsubscribe = NgUnsubscribe.create();

  public isEagerLoading: boolean = true;
  public total;

  public rowSelectable: boolean;
  public rowSelectionMode: string;
  public contextContent;
  public contextValue;
  public contextMenuCoordinates: any = {
    x: 50,
    y: 50,
  };

  public showFilterRow: boolean = false;
  public infoText: string = "list.results";
  public wikiLink: string;
  public contentVisible: boolean = true;

  public dataType;
  public identifierCol;
  public availableDataTypes: any[] = [];
  public initialDataType: string;
  public reloadOnDataTypeChange: boolean;

  public columns: DataListColumnsService;
  public listService: DataListService;

  public columnSelector: ColumnSelectorCallback;

  public widgetSortingStrategy = new WidgetSortingStrategy();
  public viewModeOptions;
  public selectedViewMode;
  public globalFilterValue: string;
  public globalFilterInput: boolean;
  public selectedDataType: string;
  public lastSelectedCells: GridSelectionRange;
  public groupingEnabled: boolean;
  public viewPortHeight: number =
    window.innerHeight ||
    document.documentElement.clientHeight ||
    document.body.clientHeight;
  public tableHeight: string;
  public frameHeight: number = DEFAULT_FRAME_HEIGHT_PX;
  public rowPinningEnabled: boolean = false;
  public heightModifier: number = 0;
  public tableGridHeight: string;
  public tableGridWidth: string;

  protected dataInitialized: boolean = false;
  protected editedRows: DataListEditedRows = {};
  public selectOptions;

  private disableContextMenu: boolean;
  private cellSelectable: boolean;
  private getNextPageOnLazyLoad: boolean;
  private pageLimitPerScroll: number;
  private sortBy: SortBy[];
  private tableHeightRelativeToRows: boolean;
  private tableHeightVisibleRows: number;
  public density: DisplayDensity = DisplayDensity.compact;
  public _primaryKey: string;
  public toggleButtonLabel: string;
  public clipboardOptions: any;
  public tileRedirectLink: string;
  public overrideTileClickEvent: boolean;
  public selectAllCheckbox: boolean = false;
  public rowSelectionType = "multiple";
  private clearSortingAndFilteringOnReset: boolean;
  public storingEnabled: boolean = false;
  public showAllColumns: boolean = true;
  public hideFilters: boolean = false;
  public showActionsInTableColumn: boolean = false;
  public removeColumnHeader: boolean;
  public noopFilterStrategy = NoopFilteringStrategy.instance();
  public noopSortStrategy = NoopSortingStrategy.instance();
  private customFilter = CustomFilteringOperand.instance();

  constructor(
    protected localStorageService: LocalStorageService,
    protected dialog: DialogService,
    protected notificationService: CustomNotificationService,
    protected translateService: TranslateService,
    public currentLocaleService: CurrentLocaleService,
    protected widgetFrameService: WidgetframeService,
    protected appContext: AppContext,
    protected appdataStore: AppdataStore,
    protected cdr: ChangeDetectorRef,
    protected http: HttpClient,
    protected progressbarService: ProgressbarService,
    protected editAttributeService: EditAttributeService,
    protected scrollService: ScrollService,
    protected dataListExportService: DataListExportService,
    protected websocketService: WebsocketService,
    protected userService: UserService,
    protected dataListEndEditService: DataListEndEditService,
    protected validationService: ValidationService,
    protected unsavedChangesService: UnsavedChangesService,
    @Optional() protected appService: AppService,
    @Inject(NOVOMIND_MODULE_DESCRIPTOR) private module: NmModuleDescriptor
  ) {}

  protected dataLoaded(data) {
    this.editedRowsOutput.next({});
    this.editedRows = {};
    if (this.grid) {
      this.grid.reflow();
      this.setStaticHeight();
    }

    this.currentData.emit(data);

    if (this.configuration.visibleDataColumnsSelection) {
      let showAll: boolean = false;
      if (this.selectedDataType != "attributes") {
        showAll = true;
      }
      this.onDataColumnsChange(this.visibleDataColumns, showAll);
    }

    if (this.grid) {
      this.grid.verticalScroll.cdr.detectChanges();
      this.grid.verticalScrollContainer.cdr.detectChanges();
      this.grid.cdr.detectChanges();
      this.cdr.detectChanges();
      if (this.globalFilterValue) {
        this.onFilterValueChange();
      }
      this.currentDataChannel.next(
        this.grid.dataView ? this.grid.dataView : this.grid.data
      );
      this.onRowSelection({ newSelection: this.grid.selectedRows });
    }

    this.dataLoadedOutput.next();
    this.autosizeColumns();
    this.dataListStateDirective.restoreGridState();
  }

  private autosizeColumns() {
    if (!this.grid) {
      return;
    }

    const autosizableColumns = this.columns.autosizableColumns();

    if (!autosizableColumns || autosizableColumns.length == 0) {
      return;
    }

    this.grid.columnList
      .filter((column: IgxColumnComponent) =>
        autosizableColumns.includes(column.field)
      )
      .forEach((column: IgxColumnComponent) => {
        if (!column.headerCell) {
          return;
        }

        column.autosize(true);
      });
  }

  public getGridColumnWidth(column: Column) {
    if (!this.grid) {
      return column.width;
    }

    const gridColumn = this.grid.getColumnByName(column.field);
    return gridColumn?.width ? gridColumn?.width : column.width;
  }

  public setStaticHeight(newrows: number = 0) {
    if (this.configuration.dynamicTableHeight) {
      return;
    }

    if (
      this.configuration.tableGridHeight ||
      this.configuration.tableGridHeight === null
    ) {
      return;
    }

    if (newrows === 0) {
      newrows = this.tableHeightVisibleRows;
    }
    setTimeout(() => {
      let height =
        (this.grid.data.length + newrows <= 10
          ? this.grid.data.length + newrows
          : 10) *
          this.grid.rowHeight +
        70;
      height = height > 100 ? height : 100;
      this.grid.height = height.toString() + "px";
      this.grid.cdr.detectChanges();
    }, 1);
  }

  public ngOnInit() {
    this._primaryKey = this.primaryKey(this.configuration);
    this.toggleButtonLabel = getOrDefault(
      this.configuration.toggleButtonLabel,
      ""
    );
    this.tileRedirectLink = this.configuration.tileRedirectLink;
    this.overrideTileClickEvent = getOrDefault(
      this.configuration.overrideTileClickEvent,
      false
    );
    this.tileIdentifierField = getOrDefault(
      this.configuration.tileIdentifierField,
      "identifier"
    );
    this.attributeUrl = this.configuration.attributeUrl;
    this.attributesDataType = this.configuration.attributesDataType;
    this.tableWidth = getOrDefault(this.configuration.tableWidth, "100%");
    this.frameHeight = getOrDefault(
      this.configuration.frameHeight,
      DEFAULT_FRAME_HEIGHT_PX
    );
    this.tableHeightRelativeToRows = getOrDefault(
      this.configuration.tableHeightRelativeToRows,
      false
    );
    this.removeColumnHeader = getOrDefault(
      this.configuration.removeColumnHeader,
      false
    );

    this.tableHeightVisibleRows = getOrDefault(
      this.configuration.tableHeightVisibleRows,
      0
    );

    this.applyDensityFromLocalStorage();
    this.availableDataTypes = getOrDefault(
      this.configuration.availableDataTypes,
      []
    );

    this.columns = new DataListColumnsService(
      <DataListConfiguration>this.configuration,
      this.appService,
      this.translateService
    );

    this.listService = new DataListService(
      this.http,
      this.progressbarService,
      this.notificationService,
      this.translateService,
      this.columns,
      this.websocketService,
      this.localstorageShownAttributesEntry,
      this.userService
    );

    if (this.localeChannel.value) {
      this.listService.selectedLocale = this.localeChannel.value;
    }

    this.columns.dynamicColumns
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => this.dynamicColumnsOutput.next(data));
    this.listService.totalSubject
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => this.totalOutput.next(data));
    this.rowSelectable = getOrDefault(this.configuration.rowSelectable, true);
    this.rowSelectionMode = getOrDefault(
      this.configuration.rowSelectionMode,
      "multiple"
    );
    this.isEagerLoading =
      "eager" == getOrDefault(this.configuration.loadingMode, "eager");
    this.globalFilterInput = getOrDefault(
      this.configuration.globalFilterInput,
      true
    );
    this.groupingEnabled = getOrDefault(
      this.configuration.groupingEnabled,
      true
    );
    this.disableContextMenu = getOrDefault(
      this.configuration.disableContextMenu,
      false
    );
    this.cellSelectable = getOrDefault(this.configuration.cellSelectable, true);
    this.getNextPageOnLazyLoad = getOrDefault(
      this.configuration.getNextPageOnLazyLoad,
      false
    );
    this.rowPinningEnabled = getOrDefault(
      this.configuration.rowPinningEnabled,
      false
    );
    this.pageLimitPerScroll = this.configuration.pageLimitPerScroll;
    this.initialDataType = this.configuration.initialDataType;
    //quickFilter || excelStyleFilter || inlineFilter
    this.filterMode = getOrDefault(
      this.configuration.filterMode,
      "excelStyleFilter"
    );
    this.reloadOnDataTypeChange = getOrDefault(
      this.configuration.reloadOnDataTypeChange,
      true
    );

    this.clearSortingAndFilteringOnReset = getOrDefault(
      this.configuration.clearSortingAndFilteringOnReset,
      false
    );

    this.tableGridHeight = getOrDefault(
      this.configuration.tableGridHeight,
      "100%"
    );

    this.tableGridWidth = getOrDefault(
      this.configuration.tableGridWidth,
      "100%"
    );

    if (this.isEagerLoading && this.configuration.eagerLimit) {
      this.listService.setEagerLimit(this.configuration.eagerLimit);
    }

    if (this.configuration.visibleDataColumnsSelection) {
      this.visibleDataColumnsStorage =
        this.localStorageService.getLocalStorageEntry(
          "visibleDataColumns" + this.configuration.title,
          Scope.USER_AND_CLIENT,
          DeletionMode.RESET
        );
      if (this.visibleDataColumnsStorage.exists()) {
        this.visibleDataColumns = JSON.parse(
          this.visibleDataColumnsStorage.value
        );
      } else {
        this.visibleDataColumns = this.configuration.visibleDataColumnsDefault;
      }
    }

    if (this.availableDataTypes.length > 0) {
      this.selectedDataType = this.availableDataTypes[0];
    }

    if (this.dataTypeModeChannel.value === "choose") {
      this.selectedDataTypeStorage =
        this.localStorageService.getLocalStorageEntry(
          "selectedDataType" + this.configuration.title,
          Scope.USER_AND_CLIENT,
          DeletionMode.RESET
        );
    }

    if (this.selectedDataTypeStorage.exists()) {
      this.selectedDataType = JSON.parse(this.selectedDataTypeStorage.value);
    } else if (this.initialDataType) {
      this.selectedDataType = this.initialDataType;
    } else {
      this.selectedDataType = this.availableDataTypes[0];
    }

    this.listService.initialize(
      this.grid,
      this.isEagerLoading,
      this.configuration,
      (data) => this.dataLoaded(data),
      this.cdr,
      this.selectedDataType
    );

    this.dataTypeOutput.next(this.selectedDataType);
    this.listService.setNextPage(this.getNextPageOnLazyLoad);
    this.listService.setPageLimit(this.pageLimitPerScroll);

    this.gridOutput.emit(this.grid);

    if (this.configuration.columnSelector) {
      this.columnSelector = ColumnSelectorCallbackRegistry.get(
        this.configuration.columnSelector
      );
    }

    this.viewModeLocalStorage = this.localStorageService.getLocalStorageEntry(
      this.configuration["title"] + "-viewMode",
      Scope.USER_AND_CLIENT,
      DeletionMode.RESET
    );

    if (this.configuration.viewModeSelection) {
      if (this.configuration.viewModeOptions) {
        this.viewModeOptions = this.configuration.viewModeOptions;
      } else if (this.configuration.viewModeSelection) {
        this.viewModeOptions = [];
        this.viewModeOptions.push({
          identifier: "listView",
          description: "button.list-view",
          icon: "view_list",
        });
        this.viewModeOptions.push({
          identifier: "tileView",
          description: "button.tile-view",
          icon: "view_module",
        });
      }

      if (this.viewModeLocalStorage.exists()) {
        this.selectedViewMode = this.viewModeOptions.filter(
          (mode) =>
            mode.identifier === JSON.parse(this.viewModeLocalStorage.value)
        )[0];
      }

      if (!this.selectedViewMode && this.configuration.viewModeSelection) {
        this.selectedViewMode = this.viewModeOptions[0];
      }
      this.viewModeOutput.next(this.selectedViewMode.identifier);

      this.listService.setViewmode(this.selectedViewMode.identifier);
    }
    this.setDefaultGroupingExpression();
    this.setDefaultSortingExpressions();

    if (this.configuration.pinnedRows) {
      this.configuration.pinnedRows.forEach((row) => this.grid.pinRow(row));
    }

    this.lastUriLocalStorage = this.localStorageService.getLocalStorageEntry(
      "last-uri-1" + this.configuration.title,
      Scope.USER_AND_CLIENT,
      DeletionMode.RESET
    );
    if (this.configuration.localStorageShownAttributes) {
      this.localstorageShownAttributesEntry =
        this.localStorageService.getLocalStorageEntry(
          this.configuration.localStorageShownAttributes,
          Scope.USER_AND_CLIENT,
          DeletionMode.NEVER
        );
    }

    if (this.configuration.dynamicColumnLink) {
      this.widgetFrameService
        .getData(this.configuration.dynamicColumnLink)
        .subscribe((attributes) => {
          // TODO This wont play nicely with localstorage recovery, since it will just override it :(
          this.columns.updateColumns(attributes._embedded.attributes);
        });
    }

    this.clipboardOptions = Object.assign(
      {},
      DEFAULT_CLIPBOARD_OPTIONS,
      this.configuration.clipboardOptions
    );

    this.tableHeight = this.getTableHeight();

    this.localeChannel.pipe(takeUntil(this.unsubscribe)).subscribe((locale) => {
      this.updateDataLocale(locale);
    });

    if (this.configuration.exportPath) {
      this.dataListExportService.exportPath = this.configuration.exportPath;
    }

    this.scrollService
      .isToolBoxEditBarVisible()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => {
        if (this.configuration.tableHeight) {
          return;
        }
        if (data && data.active && !!data.context) {
          this.heightModifier = DEFAULT_EDIT_BAR_HEIGHT_PX;
        } else {
          this.heightModifier = 0;
        }
        // this.tableHeight  = String(this.viewPortHeight - this.frameHeight - this.heightModifier) + 'px';
        this.cdr.markForCheck();
      });

    this.scrollService
      .getChangeViewPortSize()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((newViewPortHeight) => {
        this.viewPortHeight = newViewPortHeight;
        // Waiting for  sidebar animation to finish to adjust width;
        setTimeout(() => {
          this.grid.reflow();
        }, 200);
      });

    this.localstorageColumnsEntry =
      this.localStorageService.getLocalStorageEntry(
        "ColumnsEntry",
        Scope.USER_AND_CLIENT,
        DeletionMode.NEVER
      );

    if (
      this.localstorageShownAttributesEntry &&
      this.localstorageShownAttributesEntry.exists()
    ) {
      this.columns.shownAttributes = JSON.parse(
        this.localstorageShownAttributesEntry.value
      );

      this.columns.updateColumns(this.columns.shownAttributes);
      this.shownAttributesOutput.next(this.getShownAttributes());
    }

    if (this.localstorageColumnsEntry.exists()) {
      this.grid.columnList["_results"] = JSON.parse(
        this.localstorageColumnsEntry.value
      );
    }

    this.appdataStore.getAppdata().subscribe((appData) => {
      this.showActionsInTableColumn =
        appData[this.module.identifier].configuration.showActionsInTableColumn;
    });

    this.subscribeToInputs();

    this.sortBy = this.configuration.sortBy;
    this.grid.outlet = this.outlet;

    //Disable filter and sorting strategy if remote loading
    if (!this.isEagerLoading) {
      this.grid.sortStrategy = this.noopSortStrategy;
      this.grid.filterStrategy = this.noopFilterStrategy;
    }
  }

  protected updateDataLocale(locale) {
    if (this.listService) {
      this.listService.selectedLocale = locale;
      this.listService.processData(true);
    }
  }

  protected updateLocale(locale) {
    this.listService.reloadGrid();
    this.columns.updateDynamicColumnsHeaders(locale);
  }

  private setDefaultGroupingExpression() {
    if (this.configuration.groupingExpressions) {
      this.configuration.groupingExpressions.forEach((expression) => {
        const dir =
          expression.direction === "asc"
            ? SortingDirection.Asc
            : SortingDirection.Desc;
        let strategy = DefaultSortingStrategy.instance();

        this.groupingExpressions.push({
          dir,
          fieldName: expression.field,
          ignoreCase: false,
          strategy,
          groupingComparer: strategy.compareValues,
        });
      });
    }
  }

  private setDefaultSortingExpressions() {
    if (this.configuration.sortingExpressions) {
      this.configuration.sortingExpressions.forEach((expression) => {
        const dir =
          expression.direction === "asc"
            ? SortingDirection.Asc
            : SortingDirection.Desc;
        this.sortingExpressions.push({
          dir,
          fieldName: expression.field,
        });
      });
    }
  }

  protected clearSelectedRows() {
    this.selectedItems.next(null);
    if (this.grid.data) {
      this.grid.deselectAllRows();
    }
  }

  protected doReset() {
    this.clearSelectedRows();
    this.listService.reset();
  }

  public doReload(force: boolean = false) {
    this.unsavedChangesService
      .leaveContext(UNSAVED_CHANGES_DIALOG_CONFIG)
      .subscribe((response) => {
        if (!response) {
          return;
        }
        this.listService.reloadGrid(force);
        if (this.grid.data) {
          this.grid.deselectAllRows();
          this.onRowSelection({ newSelection: this.grid.selectedRows });
        }
      });
  }

  public doRefresh() {
    let selectedRows = this.grid.selectedRows;
    this.listService.reloadGrid();
    if (selectedRows) {
      this.grid.selectRows(selectedRows, true);
      this.onRowSelection({ newSelection: this.grid.selectedRows });
    }
  }

  public onDataTypeChange(reload: boolean = true) {
    this.unsavedChangesService
      .leaveContext(UNSAVED_CHANGES_DIALOG_CONFIG)
      .subscribe((response) => {
        if (!response) {
          return;
        }
        if (this.grid.data) {
          this.grid.deselectAllRows();
        }
        this.selectedDataTypeStorage.value = JSON.stringify(
          this.selectedDataType
        );
        this.listService.setDataType(
          this.selectedDataType,
          this.reloadOnDataTypeChange && reload
        );

        this.dynamicPrefixOutput.next(this.getDynamicPrefix());
        this.dataTypeOutput.next(this.selectedDataType);
        this.emitDataListStatus("dataType");
      });
  }

  private emitDataListStatus(lastChange: string) {
    this.statusOutput.next({
      lastChange,
      attributes: this.getShownAttributes(),
      dataType: this.selectedDataType,
    });
  }

  public ngAfterViewInit() {
    this.updateTranslations();
    if (this.selectedViewMode) {
      this.onViewModeChange();
    }
    this.grid.groupRowTemplate = this.groupRowTemplate;
    setTimeout(() => {
      this.grid.reflow();
    }, 200);

    if (this.sortBy) {
      this.doInitialSorting();
    }
    this.apiEmitter.next(new DataListApiImpl(this, this.configuration));

    this.emitDataListStatus(null);

    this.dataChannel.pipe(takeUntil(this.unsubscribe)).subscribe((value) => {
      if (this.listService) {
        this.listService.updateData(value, 0, true);
        this.listService.totalSubject.next(value.length);
        this.currentData.emit(value);
        this.setStaticHeight();
        this.grid.cdr.detectChanges();
        this.cdr.detectChanges();
        this.validateList(null, null);
      }
    });
    this.emitDataListStatus(null);
  }

  private doInitialSorting() {
    let sortingExpressions: ISortingExpression[] = [];

    this.sortBy.forEach((element) => {
      let columnId = element.field;
      let sortDirection = element.direction;

      if (sortDirection && columnId) {
        let direction = this.getSortDirection(sortDirection.toLowerCase());
        sortingExpressions.push({
          fieldName: columnId,
          dir: direction,
          ignoreCase: true,
        });
      }
    });

    this.grid.sortingExpressions = sortingExpressions;
  }

  private getSortDirection(direction) {
    if (direction === "asc") {
      return SortingDirection.Asc;
    } else if (direction === "desc") {
      return SortingDirection.Desc;
    } else {
      return SortingDirection.None;
    }
  }

  protected subscribeToInputs() {
    this.shownAttributesInputChannel
      .pipe(
        takeUntil(this.unsubscribe),
        filter((data) => !!data)
      )
      .subscribe((attributes) => {
        this.updateDynamicColumns(attributes);
      });

    this.reloadChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((force) => {
        this.doReload(force);
      });

    this.dataTypeModeChannel.pipe(takeUntil(this.unsubscribe)).subscribe(() => {
      this.dynamicPrefixOutput.next(this.getDynamicPrefix());
    });

    this.inputChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((link) => {
        this.storingEnabled = false;

        if (
          this.configuration.reloadWithUnsavedChanges === false &&
          this.editedRows &&
          Object.keys(this.editedRows).length !== 0
        ) {
          const dialogRef = this.dialog.open(ConfirmationDialogComponent);
          dialogRef.componentInstance.message = this.translateService.instant(
            "message.confirmation.unsavedChanges"
          );
          dialogRef.componentInstance.title =
            this.translateService.instant("hl.confirmation");
          dialogRef.componentInstance.buttonAcceptTitle = "button.accept";
          dialogRef.componentInstance.buttonCancelTitle = "button.cancel";
          dialogRef.afterClosed().subscribe((data) => {
            if (data) {
              this.handleInput(link);
            }
          });
          return;
        }
        this.handleInput(link);
      });

    this.refreshRows.pipe(takeUntil(this.unsubscribe)).subscribe((data) => {
      const primaryKey = this.primaryKey(this.configuration);
      const keys = data.map((entry) => entry[primaryKey]);
      this.reRender(keys);
    });

    this.dynamicColumnsInSubject
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => {
        //Treat these columns as if those are coming from the backend,
        // since columns coming from the backend will always be accepted
        this.columns.updateColumns(data, true);
      });

    this.productChannel.pipe(takeUntil(this.unsubscribe)).subscribe((data) => {
      this.listService.products = data;
    });

    this.attributeUrlChannel
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((url) => (this.attributeUrl = url));

    this.resetEditDataChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.editedRows = {};
        this.editedRowsOutput.next({});
        this.currentData.emit(this.grid.data);
      });

    this.resetChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.doReset();
        if (this.sortBy) {
          this.doInitialSorting();
        }
        if (this.clearSortingAndFilteringOnReset) {
          this.clearAllFiltersAndSorting();
        }
      });

    this.exportChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => {
        this.onExport(data);
      });

    this.currentLocaleService
      .getCurrentLocale()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((locale) => {
        this.updateLocale(locale);
      });

    this.translateService.onLangChange
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((transObj) => {
        this.updateTranslations(transObj);
      });

    this.disableCellEditModeChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        const selectedCells = this.grid.selectedCells;
        Object.keys(selectedCells).forEach((key) => {
          let cell = this.grid.getCellByColumn(
            selectedCells[key].cellID.rowIndex,
            selectedCells[key].column.field
          );
          cell.editMode = false;
        });
      });

    this.clearCellSelectionChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        if (this.grid.selectedCells.length > 0) {
          this.grid.clearCellSelection();
        }
      });

    this.clearRowSelectionChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.clearSelectedRows();
      });

    this.rowSelectionChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((rows) => {
        if (rows) {
          this.grid.deselectAllRows();
          this.grid.selectRows(rows);
          this.onRowSelection({ newSelection: this.grid.selectedRows });
        }
      });

    this.clearFiltersAndSortingChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.clearAllFiltersAndSorting();
      });

    this.endGridEditChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.grid.endEdit(true);
      });

    this.listService.dataLoaded
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((data) => {
        if (!this.dataInitialized) {
          this.dataInitialized = true;
        } else if (this.isEagerLoading && this.tableHeightRelativeToRows) {
          return;
        }
      });

    this.dataTypeInputChannel
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((dataType) => {
        this.selectedDataType = dataType;
        this.onDataTypeChange(this.reloadOnDataTypeChange);
      });

    this.eagerLimitChannel
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((eagerLimit) => {
        this.listService.setEagerLimit(eagerLimit);
      });

    this.filterColumnsChannel
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((columns) => {
        this.tableWidth = columns.length === 1 ? null : "100%";
        this.grid.columns.forEach((column) => {
          column.hidden = columns.indexOf(column.field) === -1;
          return column;
        });
        this.grid.reflow();
        this.grid.cdr.detectChanges();
      });

    this.preselectAttributeProfileChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((profile) => (this.preselectAttributeProfile = profile));
  }

  protected handleInput(link) {
    this.grid.navigateTo(0, 0);
    this.clearAllFiltersAndSorting(true, false, this.restoreGlobalFilter.value);
    this.onInput(link);
    if (this.sortBy) {
      this.doInitialSorting();
    }
  }

  public reRender(ids: string[]) {
    const primaryKey = this.primaryKey(this.configuration);
    this.listCells
      .filter((cell) => ids.indexOf(cell.row[primaryKey]) !== -1)
      .forEach((cell) => {
        cell.update();
      });
  }

  protected onInput(link) {
    if (this.columns && this.columns.shownAttributes) {
      this.columns.updateColumns(this.columns.shownAttributes);
    }
    this.listService.updateLink(link);
  }

  public primaryKey(configuration: DataListTreeConfiguration): string {
    return configuration.primaryKey || "identifier";
  }

  public onRowEdit(
    event: IGridEditEventArgs,
    configuration: DataListConfiguration = this.configuration,
    parent: string = null
  ) {
    this.rowEditLeaveEmitter.next();
    if (!configuration.rowEditable && parent == null) {
      return;
    }

    const attributes = {};

    for (const identifier in event.newValue) {
      if (!event.newValue.hasOwnProperty(identifier)) {
        continue;
      }

      if (!event.oldValue.hasOwnProperty(identifier)) {
        attributes[identifier] = event.newValue[identifier];
        continue;
      }

      let oldChanges =
        event.oldValue[identifier] && event.oldValue[identifier].changes
          ? event.oldValue[identifier].changes
          : 0;
      let newChanges =
        event.newValue[identifier] && event.newValue[identifier].changes
          ? event.newValue[identifier].changes
          : 0;

      if (oldChanges != newChanges) {
        attributes[identifier] = event.newValue[identifier];
      }
    }

    this.fireEditedRowsEvent(
      event.rowID,
      event.newValue,
      parent,
      attributes,
      configuration
    );
  }

  onCellEdit(
    event: IGridEditEventArgs,
    configuration: DataListConfiguration = this.configuration
  ) {
    if (configuration.rowEditable) {
      return;
    }

    let row = this.grid.getRowByKey(event.rowID);

    if (
      event.oldValue &&
      (event.oldValue === event.newValue ||
        (event.oldValue.value && event.oldValue.value === event.newValue.value))
    ) {
      return;
    }

    // try to find identifier, even if the new value is null/undefined
    let value = event.newValue || event.oldValue;

    let identifier = null;
    if (value) {
      identifier = value.identifier ? value.identifier : value;
    }

    if (!value || !identifier) {
      return;
    }

    const attributes = { [identifier]: event.newValue };
    this.fireEditedRowsEvent(
      event.rowID,
      row.rowData,
      null,
      attributes,
      configuration
    );
  }

  public fireEditedRowsEvent(
    rowId: string,
    gridRow: any,
    parent: string,
    attributes,
    configuration: DataListConfiguration
  ) {
    this.setEditedRowsData(rowId, gridRow, parent, attributes, configuration);
    this.editedRowsOutput.next(this.editedRows);
    this.currentData.emit(this.grid.data);
  }

  protected setEditedRowsData(
    rowId: string,
    row: any,
    parent: string,
    attributes,
    configuration: DataListConfiguration
  ) {
    const metadata = configuration.metadataKeys
      ? configuration.metadataKeys.map((key) => row[key])
      : [];
    if (this.editedRows[rowId]) {
      Object.keys(attributes).forEach((key) => {
        this.editedRows[rowId].attributes[key] = attributes[key];
        this.editedRows[rowId].row = row;
      });
    } else {
      this.editedRows[rowId] = { parent, attributes, row };
      //Hide metadata from the public interface since it should no longer be used (you can always directly access the row on the event object
      this.editedRows[rowId]["metadata"] = metadata;
    }
    this.editedRowOutput.next(this.editedRows[rowId]);
  }

  private updateTranslations(transObj?: LangChangeEvent) {
    if (!this.grid) {
      return;
    }
    Object.keys(this.grid.resourceStrings).forEach((key) => {
      let value = transObj
        ? transObj.translations[key]
        : this.translateService.instant(key);
      if (value) {
        this.grid.resourceStrings[key] = value;
      }
    });
  }

  public editShownAttributes() {
    this.unsavedChangesService
      .leaveContext(UNSAVED_CHANGES_DIALOG_CONFIG)
      .subscribe((response) => {
        if (!response) {
          return;
        }
        this.openDialogForShownAttributes();
      });
  }

  public openDialogForShownAttributes() {
    let dialogConf = {
      minWidth: "900px",
      maxWidth: "900px",
      height: this.configuration.profileUrl ? "860px" : "755px",
    };

    let dialogRef = this.dialog.open(
      SelectAttributesDialogComponent,
      dialogConf
    );

    dialogRef.componentInstance.infoText = "infoText.select.attributes";
    dialogRef.componentInstance.showRestrictToCategoryButton = getOrDefault(
      this.configuration.showRestrictToCategoryButton,
      false
    );
    dialogRef.componentInstance.profileUrl = this.configuration.profileUrl;
    dialogRef.componentInstance.preselectAttributeProfile =
      this.preselectAttributeProfile;
    dialogRef.componentInstance.restrictAttributesToCategoryOnAttributeDialogOpen =
      getOrDefault(
        this.configuration.restrictAttributesToCategoryOnAttributeDialogOpen,
        false
      );
    dialogRef.componentInstance.preselectedAttributes =
      this.getShownAttributes();
    dialogRef.componentInstance.enableSorting = true;
    dialogRef.componentInstance.currentLocale =
      this.currentLocaleService.currentLocale;
    dialogRef.componentInstance.additionalProperties = getOrDefault(
      this.configuration.selectAttributeAdditionalProperties,
      ["type", "group", "dataLevels"]
    );
    dialogRef.componentInstance.selectFilterParams =
      this.configuration.selectFilterParams;
    dialogRef.componentInstance.maxAttributes = getOrDefault(
      this.configuration.selectAttributeMaxAttributes,
      100
    );

    dialogRef.componentInstance.emptySelection = getOrDefault(
      this.configuration.selectAttributeEmptySelection,
      null
    );

    if (this.attributesDataType) {
      dialogRef.componentInstance.dataType = this.attributesDataType;
    }

    if (this.listService.products) {
      dialogRef.componentInstance.restrictParameters = {
        cacheId: null,
        products: this.listService.products,
      };
    } else if (
      this.configuration.productNumberField &&
      this.listService.dataArray &&
      this.listService.dataArray.length !== 0
    ) {
      const products = this.listService.dataArray.map(
        (entry) => entry[this.configuration.productNumberField]
      );
      dialogRef.componentInstance.restrictParameters = {
        cacheId: this.listService.cacheId,
        products,
      };
    }
    dialogRef.componentInstance.attributeUrl = throwIfUndefined(
      this.attributeUrl
    );

    dialogRef.componentInstance.attributeUrlParams = this.attributeUrlParams;

    dialogRef.afterClosed().subscribe((attributes) => {
      if (attributes) {
        this.storingEnabled = false;
        let columns = this.grid.columns
          .sort((a, b) => a.visibleIndex - b.visibleIndex)
          .map((column) => Attributes.fromField(column.field));

        let attributeIdentifier = attributes.map(
          (attribute) => attribute.identifier
        );

        let sorted = columns.sort((a, b) => {
          return (
            attributeIdentifier.indexOf(a) - attributeIdentifier.indexOf(b)
          );
        });

        this.columns.columnOrder.next(sorted);
        this.dataListStateDirective.storeOrder(sorted);
        this.updateDynamicColumns(attributes);
        this.shownAttributesOutput.next(this.getShownAttributes());
        this.emitDataListStatus("attributes");
        this.storingEnabled = false;
      }
    });
  }

  protected getShownAttributes() {
    const sortedColumns = this.grid.columns
      .sort((a, b) => a.visibleIndex - b.visibleIndex)
      .map((attribute) => Attributes.fromField(attribute.field));

    return this.columns.shownAttributes.sort((a, b) => {
      return (
        sortedColumns.indexOf(a.identifier) -
        sortedColumns.indexOf(b.identifier)
      );
    });
  }

  /**
   * Function that gets called everytime the columns get updated from the SelectAttributesDialogComponent. Will directly call setDynamicColumns, if not overwritten
   */
  public updateDynamicColumns(attributes) {
    this.setDynamicColumns(attributes);
  }

  protected setDynamicColumns(attributes) {
    this.columns.shownAttributes = deepCopy(attributes);
    this.columns.updateColumns(attributes);
    if (this.configuration.dynamicColumnsFromData) {
      this.doReload();
    }
    if (this.localstorageShownAttributesEntry) {
      this.localstorageShownAttributesEntry.value = JSON.stringify(attributes);
    }
  }

  public onExport(settings) {
    let exportData = !this.isEagerLoading ? this.listService.cachedData : null;
    this.dataListExportService.export(
      this.grid,
      settings,
      this.configuration.title,
      this.configuration.useIgxExport,
      exportData
    );
  }

  public ngOnDestroy() {
    if (!this.configuration.keepOnPageChangeIdentifier) {
      this.columns.destroy();
      this.listService.ngOnDestroy();
    }
    this.unsubscribe.destroy();
  }

  onCellClick(event) {
    this.onCellSelect.next(event.cell);
    // use navigateTo to ensure that cell is ready for past and tbody gets focused
    if (!event?.cell?.editMode) {
      this.grid.navigateTo(
        event?.cell?.row?.index,
        event?.cell?.column?.visibleIndex,
        (args) => {
          args?.target?.activate();
          this.grid.tbody.nativeElement.focus();
        }
      );
    }

    if (this.configuration.rowSelectable !== false) {
      return;
    }
    if (event.cell.row.isSelected) {
      this.grid.deselectRows([event.cell.row.rowID]);
    } else if (this.cellSelectable) {
      this.grid.selectRows([event.cell.row.rowID], true);
    }

    this.onRowSelection({ newSelection: this.grid.selectedRows });
  }

  public onRowSelection(event: any) {
    const params = this.buildSelectionEvent(event, this.grid, this.listService);
    this.selectedItems.next(params);
  }

  onHeaderSelectorClick(event: any) {
    const params = this.buildLazyAllSelectionEvent(
      event,
      this.grid,
      this.listService
    );
    this.selectedItems.next(params);
  }

  protected buildLazyAllSelectionEvent(
    event: any,
    grid: IgxGridBaseDirective,
    service: DataListService
  ): SelectionParams {
    let result: SelectionParams = { cacheId: service.cacheId };
    this.selectAllCheckbox =
      this.selectAllCheckbox === null && event.checked ? false : event.checked;
    if (!this.selectAllCheckbox) {
      result = {
        count: 0,
        rows: [],
      };
      grid.deselectAllRows();
      if (service.configuration.emitSelectedItems) {
        result.rowData = [];
      }
      let rowData = service.cachedData.filter((data) => !data.cache);
      rowData.forEach((row) => (row.selected = false));
    } else {
      let rowData = service.cachedData.filter((data) => !data.cache);
      rowData.forEach((row) => (row.selected = true));
      if (rowData) {
        result = this.selectAvailableRows(result, grid, service, rowData);
      }
    }
    return result;
  }

  protected buildSelectionEvent(
    event: any,
    grid:
      | IgxGridComponent
      | IgxHierarchicalGridComponent
      | IgxTreeGridComponent,
    service: DataListService
  ): SelectionParams {
    let result: SelectionParams = {
      count: event.newSelection ? event.newSelection.length : 1,
      rows: event.newSelection,
      cacheId: service.cacheId,
    };

    let primaryKey = this.primaryKey(service.configuration);
    if (service.configuration.emitSelectedItems && service.isEagerLoading) {
      let selection = new Set(event.newSelection);

      result.rowData = grid.data.filter((data) =>
        selection.has(data[primaryKey])
      );
    } else if (!service.isEagerLoading) {
      let rowData = service.cachedData;
      if (event.removed && event.removed.length > 0) {
        let removed = new Set(event.removed);
        rowData
          .filter((data) => removed.has(data[primaryKey]))
          .forEach((row) => (row.selected = false));
      }
      if (event.added && event.added.length > 0) {
        let added = new Set(event.added);
        rowData
          .filter((data) => added.has(data[primaryKey]))
          .forEach((row) => (row.selected = true));
      }
      if (rowData) {
        result = this.selectAvailableRows(result, grid, service, rowData);
      }
    } else if (service.configuration.emitSelectedItems && result) {
      result.rowData = result.rows.map((key) => {
        return grid.getRowByKey(key).rowData;
      });
    }

    return result;
  }

  selectAvailableRows(
    result: SelectionParams,
    grid: IgxGridBaseDirective,
    service: DataListService,
    rowData: any[]
  ) {
    rowData = rowData.filter((data) => data.selected);
    result = {
      count: rowData.length,
      rows: rowData.map((data) => data[this.primaryKey(service.configuration)]),
    };
    grid.selectRows(result.rows);
    if (result.count == 0) {
      this.selectAllCheckbox = false;
      grid.deselectAllRows();
    } else if (result.count != service.cachedData.length) {
      this.selectAllCheckbox = null;
    } else {
      this.selectAllCheckbox = true;
    }

    if (service.configuration.emitSelectedItems) {
      result.rowData = rowData;
    }
    return result;
  }

  onViewModeChange() {
    this.listService.setViewmode(
      this.selectedViewMode.identifier,
      this.configuration.handleViewModeInBackend === true
    );
    this.viewModeOutput.next(this.selectedViewMode.identifier);
    this.isListMode = true;
    this.hideFilters = true;

    if (this.selectedViewMode.identifier === "listView") {
      this.hideFilters = false;
      if (
        this.columns.shownAttributes &&
        this.columns.shownAttributes.length > 0
      ) {
        this.columns.updateColumns(this.columns.shownAttributes);
      }
    } else if (this.selectedViewMode.identifier === "tileView") {
      this.isListMode = false;
      this.hideFilters = false;
      if (
        this.columns.shownAttributes &&
        this.columns.shownAttributes.length > 0
      ) {
        this.columns.updateColumns([]);
      }

      this.groupingExpressions = [];
    }

    this.viewModeLocalStorage.value = JSON.stringify(
      this.selectedViewMode.identifier
    );
    if (this.globalFilterValue) {
      this.onFilterValueChange();
    }
    this.currentDataChannel.next(
      this.grid.dataView ? this.grid.dataView : this.grid.data
    );
    this.slideChange.next(3);
  }

  public showFilteringRow(event) {
    this.showFilterRow = !this.showFilterRow;
  }

  public clearGlobalFilter() {
    this.globalFilterValue = "";
    this.grid.clearFilter();
  }

  public clearAllFiltersAndSorting(
    clearGrouping = true,
    loadData: boolean = true,
    restoreGlobalFilter = false
  ) {
    if (!restoreGlobalFilter && this.globalFilterInput) {
      this.clearGlobalFilter();
    }
    this.restoreGlobalFilter.next(false);

    this.grid.clearFilter();
    this.grid.clearSort();
    this.grid.clearCellSelection();
    this.grid.sortingExpressions = [];
    if (clearGrouping) {
      this.grid.groupingExpressions = [];
      this.setDefaultGroupingExpression();
    }

    this.setDefaultSortingExpressions();

    if (loadData) {
      this.listService.processData(true);
    }
    this.grid.cdr.detectChanges();
  }

  public trackColumns(index: number, column: Column) {
    return (
      "" +
      column.type +
      column.field +
      column.hidden +
      column.settings.columnOrder
    );
  }

  public getDynamicPrefix() {
    if (this.dataTypeModeChannel.value === "choose") {
      return this.selectedDataType + "-";
    } else {
      return "mixed" + "-";
    }
  }

  public getTranslationKey(column: Column) {
    if (column.dynamicHeader) {
      return this.getDynamicPrefix() + column.header;
    }
    return column.header;
  }

  public getColumnHeaderClasses(column: Column) {
    let cssClasses = [];

    if (column.sortable) {
      cssClasses.push("widthSorting");
    }

    if (column.headerStyle) {
      cssClasses.push(column.headerStyle);
    }

    return cssClasses;
  }

  public sortStrategy(column: Column): ISortingStrategy {
    if (column.type === "widget" && this.isEagerLoading) {
      return this.widgetSortingStrategy;
    } else {
      return DefaultSortingStrategy.instance();
    }
  }

  public groupingComparer(column: Column) {
    return null;
  }

  public onFilterValueChange() {
    this.grid.filteringLogic = FilteringLogic.Or;
    this.grid.filterGlobal(
      this.globalFilterValue,
      this.customFilter.condition("object"),
      false
    );
    this.grid.cdr.detectChanges();

    this.currentDataChannel.next(this.grid.filteredData);
  }

  onRangeSelection(event: GridSelectionRange) {
    this.lastSelectedCells = event;

    let gridData = this.grid.dataView ? this.grid.dataView : this.grid.data;

    let range = [];
    for (let i = event.rowStart; i < event.rowEnd + 1; i++) {
      if (gridData[i].identifier) {
        range.push(gridData[i].identifier);
      }
    }
    range = range.filter((id) => !!id);

    this.grid.selectRows(range, true);

    this.onRowSelection({ newSelection: range });
    this.grid.cdr.markForCheck();
  }

  public onVisibilityChanged(event) {
    if (!event.column || !event.column.field) {
      return;
    }

    let newColumns = this.columns.shownAttributes.filter((column) => {
      return (
        column.identifier !==
        this.columns.shownAttributes.filter((column) => {
          return (
            event.column.field.substr(0, event.column.field.indexOf("#")) ===
            column.identifier
          );
        })[0].identifier
      );
    });

    if (newColumns) {
      this.setDynamicColumns(newColumns);
    }
  }

  public stopPropagation(event, field) {
    event.stopImmediatePropagation();
    event.preventDefault();

    this.inputBoxes.forEach((input) => {
      if (input.nativeElement.classList.contains(field)) {
        input.nativeElement.focus();
      }
    });
    return false;
  }

  columnInit(column: any) {
    if (this.clipboardOptions.copyFormatters) {
      column.formatter = (target) => formatCellWidgets(target, "exportValue");
    }
  }

  public onColumnFilterInput(input: any, column: IgxColumnComponent) {
    this.grid.filter(
      column.field,
      input,
      this.customFilter.condition("object"),
      column.filteringIgnoreCase
    );
  }

  public clearColumnFilter(input: any, column: any) {
    this.dataListStateDirective.columnFilterInput[column.field] = null;
    this.grid.clearFilter(column.field);
  }

  public onRowEditEnter() {
    this.rowEditEnterEmitter.next();
  }

  public onRowEditCancel() {
    this.rowEditLeaveEmitter.next();
  }

  public openContextmenu(eventArgs) {
    if (!this.disableContextMenu) {
      if (eventArgs.cell && eventArgs.cell.column) {
        const columnIdentifier = eventArgs.cell.column.field;

        this.columns.columns.pipe(first()).subscribe((columns) => {
          const column = columns.find(
            (entry) => entry.field === columnIdentifier
          );
          if (column) {
            this.contextMenuColumn = column;
          }
        });
        this.contextMenuCoordinates.cell = eventArgs.cell;
      }
      if (this.lastSelectedCells) {
        this.grid.selectRange(this.lastSelectedCells);
      }
      this.contextMenuCoordinates.x = eventArgs.event.clientX + "px";
      this.contextMenuCoordinates.y = eventArgs.event.clientY + "px";
      eventArgs.event.preventDefault();
      this.menuTrigger.openMenu();
    }
  }

  closeContextMenu() {
    if (!this.disableContextMenu) {
      this.menuTrigger.closeMenu();
    }
  }

  public validateList(validation: any, configuration: DataListConfiguration) {
    if (validation) {
      let primaryKey = this.primaryKey(configuration);

      this.listCells
        .filter(
          (cell) =>
            cell.row[primaryKey] === validation.primaryKey &&
            cell.attribute &&
            cell.attribute.identifier === validation.attribute
        )
        .forEach((cell) => {
          cell.cdr.detectChanges();
        });
    }

    let isValid = this.validateAllRows();
    this.isValidOutput.emit(isValid);
  }

  protected validateAllRows(): boolean {
    return this.validateGrid(this.grid);
  }

  protected validateGrid(grid: IgxGridBaseDirective) {
    if (this.editedRows == null) {
      return true;
    }

    const rowIds = Object.keys(this.editedRows);
    for (let rowId of rowIds) {
      const attributes = this.editedRows[rowId]?.attributes;
      if (attributes == null) {
        continue;
      }

      const row = grid.data.find(
        (record) => record[this._primaryKey] === rowId
      );

      if (row == null) {
        continue;
      }

      const identifiers = Object.keys(attributes);
      for (let identifier of identifiers) {
        const value = row[Attributes.toSourceField(identifier)];
        if (value?.errors?.length > 0) {
          return false;
        }
      }
    }

    return true;
  }

  private checkCellForErrors(
    cell: ListCellEditComponent | ListCellComponent
  ): boolean {
    if (!cell.attribute) {
      return false;
    }
    let errors = cell.attribute.errors;
    return errors && errors.length > 0;
  }

  public applyDensityFromLocalStorage() {
    if (this.configuration.density) {
      this.density = <DisplayDensity>this.configuration.density;
      this.grid.displayDensity = this.density;
      return;
    }

    let densityStorage =
      this.localStorageService.getLocalStorageEntryByConfig(
        densityStorageConfig
      );
    if (densityStorage.exists()) {
      this.density = JSON.parse(densityStorage.value);
    }

    this.configuration.density = this.density;
    this.grid.displayDensity = this.density;
  }

  onCellEditEnter(event: IGridEditEventArgs) {
    this.cellEditModeActive = true;
    let field = event.column.field;
    let oldValue = event.rowData[Attributes.toSourceField(field)];

    if (!oldValue || !oldValue.identifier || oldValue["read-only"]) {
      event.cancel = true;
      return;
    }

    this.dataListEndEditService.beginEdit(this.grid);
  }

  onCellEditExit() {
    this.cellEditModeActive = false;
  }

  updateDataOutput() {
    this.grid.cdr.detectChanges();
    this.currentDataChannel.next(
      this.grid.dataView ? this.grid.dataView : this.grid.data
    );
  }

  getHeaderClass(nmColumn) {
    let classes = [];
    if (this.configuration.headerClasses) {
      for (let cssClass in this.configuration.headerClasses) {
        let ref = this.configuration.headerClasses[cssClass];
        if (
          typeof ref === "string" &&
          HeaderClassesCallbackRegistry.get(ref)(nmColumn)
        ) {
          classes.push(cssClass);
        }
      }
    }

    // default header style
    if (classes.length === 0) {
      classes.push(
        HeaderClassesCallbackRegistry.getDefaultIsMandatory()(nmColumn)
          ? "mandatoryCell"
          : "default"
      );
    }

    return classes.join(" ");
  }

  public toggleMode(event) {
    this.toggleButtonChangeEmitter.emit(event.checked);
  }

  public tileClicked(event) {
    this.tileClickedEventEmitter.emit(event);
  }

  public onItemDropped(event, cell: IgxGridCell, column: Column) {
    if (column.allowDrop == false) {
      return;
    }
    //Check the type of this event, if this is a data-list-row we know how to handle it, if the target column is of type attribute!
    if (event.dragData.type === "data-list-row") {
      if (column.type === "attribute") {
        //This is an attribute
        const value = extractAttributeFromCell(cell, column.field);

        const draggingAttribute = extractAttributeFromRow(
          event.dragData.source,
          event.dragData.column.field
        );
        if (value && draggingAttribute) {
          value.source = deepCopy(draggingAttribute.source);

          const attribute = flatCopy(value);
          Attributes.updateCell(cell, attribute);
        }
      }
    }
  }

  public getHighlightReadOnly(): boolean {
    return getOrDefault(this.configuration.highlightReadOnly, true);
  }

  public getCellClass(nmColumn) {
    let resolved: any = {};

    if (nmColumn.cellClasses) {
      for (let cssClass in nmColumn.cellClasses) {
        let ref = nmColumn.cellClasses[cssClass];
        resolved[cssClass] = ref;
        if (typeof ref === "string") {
          resolved[cssClass] = CellClassesCallbackRegistry.get(ref) || false;
        }
      }
    } else {
      // default cell style
      resolved.mandatoryCell =
        CellClassesCallbackRegistry.getDefaultIsMandatory();
    }

    resolved[nmColumn.type ? nmColumn.type : "default"] = true;

    return resolved;
  }

  getTableHeight() {
    if (this.configuration.dynamicTableHeight) {
      return this.calcTableHeight();
    }
    return "100%";
  }

  calcTableHeight() {
    let height: string;
    let modifiers = DEFAULT_MODIFIERS;

    if (this.configuration.dynamicTableHeightAdditionalModifiers) {
      modifiers = modifiers.concat(
        this.configuration.dynamicTableHeightAdditionalModifiers
      );
    }

    if (this.configuration.dynamicTableHeightContainer) {
      const selector = this.configuration.dynamicTableHeightContainer;
      let modifier = 0;

      if (this.configuration.dynamicTableHeightAdditionalHeight) {
        modifier = parseInt(
          this.configuration.dynamicTableHeightAdditionalHeight,
          10
        );
      }

      let ro = new ResizeObserver((entries, observer) => {
        for (let entry of entries) {
          const cr = entry.contentRect;
          this.tableHeight = `${cr.height - modifier}px`;
          return height;
        }
      });

      ro.observe(document.querySelector(selector));
      return;
    }

    let maxHeightContent = getBodyStyleCssProperty("max-height-content");
    height = maxHeightContent;

    if (modifiers && modifiers.length > 0) {
      height = `calc(${maxHeightContent}`;

      modifiers.forEach((modifier) => {
        height += ` - ${getBodyStyleCssProperty(modifier)}`;
      });

      if (this.configuration.dynamicTableHeightAdditionalHeight) {
        height += ` - ${this.configuration.dynamicTableHeightAdditionalHeight}`;
      }

      if (
        (this.configuration.footer && !this.configuration.footer.hidden) ||
        !this.configuration.footer
      ) {
        height += ` - ${getBodyStyleCssProperty(TABLE_FOOTER_MODIFIER)}`;
      }

      height += `)`;
    }

    return height;
  }

  public takeRecommendedAttributes(
    recommendedAttributes: RecommendedAttributes
  ) {
    const attributes = new Map<string, Attribute>();

    [
      ...recommendedAttributes.attributes,
      ...this.columns.shownAttributes,
    ].forEach((attribute) => attributes.set(attribute.identifier, attribute));

    const emptySelection: Attribute[] = getOrDefault(
      this.configuration.selectAttributeEmptySelection,
      null
    );

    if (emptySelection) {
      emptySelection.forEach((attribute) =>
        attributes.delete(attribute.identifier)
      );
    }

    this.updateDynamicColumns(Array.from(attributes.values()));
    return false;
  }

  public dataPasted(processedData: string[][]) {
    const uri =
      this.configuration.excelCopyParseUrl ||
      "/api/core/attributes/parse?include=attribute.source&include=attribute.validation";
    const cell = this.grid.selectedCells[0];
    if (!cell) {
      return;
    }
    let body = this.prepareExcelPasteRequestData(cell, processedData);

    if (
      body.needsDateTimeFormatSelection ||
      body.needsSeparatorSelection ||
      body.needsDateFormatSelection
    ) {
      const dialogConfig = UtilService.getPasteDialogue(body);
      let dialogRef = this.dialog.open(PageDialogComponent, dialogConfig);
      dialogRef.afterClosed().subscribe((data) => {
        if (data) {
          body = Object.assign(body, data);
          this.widgetFrameService.postData(uri, body).subscribe((response) => {
            this.applyExcelPasteData(response, cell);
          });
        }
      });
      return;
    }

    this.widgetFrameService.postData(uri, body).subscribe((response) => {
      this.applyExcelPasteData(response, cell);
    });
  }

  public onRowDragStart(event) {
    event.dragData.type = "data-list-row";
    return event;
  }

  public onDrop(event) {
    if (event.dragData.type !== "data-list-row") {
      return;
    }

    const originalIndex = event.drag.data.index;
    const dragRect = event.drag.ghostElement.getBoundingClientRect();
    const currRowIndex = this.getCurrentRowIndex(this.grid.rowList.toArray(), {
      x: dragRect.x,
      y: dragRect.y,
    });

    if (!currRowIndex) {
      return;
    }

    // remove the row that was dragged and place it onto its new location
    this.listService.dataArray.splice(originalIndex, 1);
    this.listService.dataArray.splice(currRowIndex, 0, event.dragData.rowData);
    this.dataChannel.next(this.listService.dataArray);

    this.reorderedRows.emit({
      rowData: event.dragData._rowData,
      currentRowIndex: currRowIndex,
      dataArray: this.listService.dataArray,
    });
  }

  private getCurrentRowIndex(rowList, cursorPosition) {
    if (rowList.length === 0) {
      return null;
    }

    const primaryKey = this.primaryKey(this.configuration);

    for (const row of rowList) {
      const rowRect = row.nativeElement.getBoundingClientRect();
      if (cursorPosition.y > rowRect.top && cursorPosition.y < rowRect.bottom) {
        // return the index of the targeted row
        return this.listService.dataArray.indexOf(
          this.listService.dataArray.find(
            (r) => r[primaryKey] === row.rowData[primaryKey]
          )
        );
      }
    }
  }

  private ALWAYS_ALLOWED_TYPES = [
    "LOCALIZED_STRING",
    "PLAIN_STRING",
    "INTEGER_NUMBER",
    "DECIMAL_NUMBER",
    "DATE",
  ];

  private prepareExcelPasteRequestData(
    selectedCell,
    processedData: string[][]
  ) {
    const pk = this.grid.primaryKey;
    const copyEverwhere = this.configuration.excelCopyPasteEverywhere;
    const cellData: any[][] = [];
    const startRowIndex = selectedCell.row.index;
    let needsDateFormatSelection = false;
    let needsDateTimeFormatSelection = false;
    let needsSeparatorSelection = false;
    const cellIndex = selectedCell.column.visibleIndex;
    const columns = this.grid.visibleColumns.sort(
      (l, r) => l.visibleIndex - r.visibleIndex
    );

    let rowIteratorIndex = 0;
    for (const curentDataRow of processedData) {
      const rowData: any[] = [];
      cellData.push(rowData);
      const dataRec = this.grid.data[startRowIndex + rowIteratorIndex];
      if (!dataRec) {
        // no rec to update, we are at the end of the list
        break;
      }
      for (
        let cellIteratorIndex = 0;
        cellIteratorIndex + cellIndex < columns.length &&
        cellIteratorIndex < curentDataRow.length;
        cellIteratorIndex++
      ) {
        let currentIndex = cellIteratorIndex + cellIndex;
        let colKey = Attributes.toSourceField(columns[currentIndex].field);

        const data = dataRec[colKey];

        if (!data) {
          //console.debug(`Cant find field ${colKey} in row`, dataRec)
          continue;
        }
        //We dont have copyeverywhere enabled and this is no attribute type that is always allowed
        if (
          !copyEverwhere &&
          this.ALWAYS_ALLOWED_TYPES.indexOf(data.type) === -1
        ) {
          continue;
        }
        //We will only write to attribute columns that are not readonly
        if (data["read-only"] !== false) {
          continue;
        }
        if (data.type === "DATE") {
          needsDateFormatSelection = true;
        } else if (data.type === "DATE_TIME") {
          needsDateTimeFormatSelection = true;
        } else if (
          data.type === "MULTI_LOOKUP" ||
          data.type === "COMPOSITION_AMOUNT" ||
          data.type === "COMPOSITION_PERCENT"
        ) {
          needsSeparatorSelection = true;
        }
        rowData[cellIteratorIndex] = data;
      }

      rowIteratorIndex++;
    }
    const body = {
      data: processedData,
      dtos: cellData,
      needsDateFormatSelection,
      needsSeparatorSelection,
      needsDateTimeFormatSelection,
    };
    return body;
  }

  private applyExcelPasteData(response, selectedCell) {
    const rowData = this.grid.data;
    let rowIteratorIndex = 0;
    const pk = this.grid.primaryKey;
    const cellIndex = selectedCell.column.visibleIndex;
    const columns = this.grid.visibleColumns;
    const startRowIndex = selectedCell.row.index;
    const params: DataListActionParameter = {
      api: new DataListApiImpl(this, this.configuration),
      export: null,
      grid: this,
    };
    response._embedded[response.type].forEach((row) => {
      const dataRec = rowData[startRowIndex + rowIteratorIndex];

      const rowPkValue = dataRec[pk];
      //We need to respect three cases here:
      // 1. Everything is fine row and cells are here
      // 2. Row wont be found - this happens if we update a row that is outside the viewport (below the current cell) -
      // 3. Cell wont be found - this happpens if we update a cell that is outside the viewport (right of the current cells)
      const igniteRow = this.grid.getRowByKey(rowPkValue);
      let cellIteratorIndex = 0;
      row._embedded[row.type].forEach((cell: { identifier: any }) => {
        if (cell == null) {
          cellIteratorIndex++;
          return;
        }
        let currentIndex = cellIndex + cellIteratorIndex;
        let colKey = Attributes.toValueField(columns[currentIndex].field);
        // If we cant find the row OR the cell skip the update
        if (!igniteRow || !this.grid.getCellByColumn(igniteRow.index, colKey)) {
          this.validationService.validateAttribute(cell);
        } else {
          updateRowOrCell(
            cell,
            igniteRow,
            colKey,
            params,
            this.validationService
          );
          cellIteratorIndex++;
        }

        dataRec[Attributes.toSourceField(cell.identifier)] = cell;

        const eventAttributeData = {
          [cell.identifier]: cell,
        };
        params.api.fireEditedRowsEvent(
          rowPkValue,
          dataRec,
          null,
          eventAttributeData
        );
      });
      rowIteratorIndex++;
    });
    this.validateList(null, null);
  }

  columnOrderChanged(columnIdentifiers: string[]) {
    this.columns.columnOrder.next(columnIdentifiers);
  }

  onDataColumnsChange(
    visibleDataColumns: string[],
    showAllColumns: boolean = false
  ) {
    this.showAllColumns = showAllColumns;
    this.visibleDataColumnsStorage.value = JSON.stringify(visibleDataColumns);
    this.visibleDataColumns = visibleDataColumns;
    this.cdr.markForCheck();
  }

  processDataOnChange(event, reset: boolean) {
    if (event) {
      this.listService.processData(reset);
      this.updateDataOutput();
    }
  }

  onFilteringDone() {
    this.unsavedChangesService
      .leaveContext(UNSAVED_CHANGES_DIALOG_CONFIG)
      .subscribe((response) => {
        if (!response) {
          return;
        }
        this.listService.processData(true);
        this.updateDataOutput();
      });
  }
}

export function formatCellWidgets(target: any, property: string): string {
  let val = "";
  if (Array.isArray(target) && target.length > 0) {
    val = target
      .map((option) => (option[property] ? option[property] : option))
      .join(" ");
  } else {
    val = String(target[property] ? target[property] : target);
  }
  return val;
}

export class WidgetSortingStrategy implements ISortingStrategy {
  public sort(
    data: any[],
    fieldName: string,
    dir: SortingDirection,
    ignoreCase: boolean
  ) {
    const cmpFunc = (a, b) => {
      return this.compareObjects(a, b, fieldName, ignoreCase, dir);
    };

    return data.sort(cmpFunc);
  }

  protected compareObjects(
    obj1: any,
    obj2: any,
    fieldName: string,
    ignoreCase: boolean,
    dir: SortingDirection
  ) {
    let a = formatCellWidgets(obj1[fieldName], "value");
    let b = formatCellWidgets(obj2[fieldName], "value");

    if (ignoreCase) {
      a = a.toLowerCase();
      b = b.toLowerCase();
    }
    return this.sortByParity(a, b, dir);
  }

  protected sortByParity(a: any, b: any, dir: SortingDirection) {
    if (a > b) return dir === 1 ? +1 : -1;
    if (a < b) return dir === 1 ? -1 : +1;
    return 0;
  }
}

export const PREFIX = "--";
export class CustomFilteringOperand extends IgxStringFilteringOperand {
  private constructor() {
    super();
    this.operations = [customObjectFilteringOperation];
  }
}

export const customObjectFilteringOperation: IFilteringOperation = {
  iconName: "contains",
  isUnary: false,
  logic: (target: any, searchVal: string, ignoreCase?: boolean) => {
    if (!target && target !== 0) {
      return false;
    }
    let val = "";
    if (Array.isArray(target) && target.length > 0) {
      val = target
        .map((option) => (option.value ? option.value : option))
        .join(" ");
    } else {
      val = String(target.value ? target.value : target);
    }
    if (ignoreCase) {
      return val.toLowerCase().indexOf(searchVal.toLowerCase()) !== -1;
    } else {
      return val.indexOf(searchVal) !== -1;
    }
  },
  name: "object",
};

/**
 * Public interface of the edited Rows
 */
export interface DataListEditedRows {
  [key: string]: DataListEditedRow;
}

export interface DataListEditedRow {
  parent: string;
  //The row that got edited
  row: any;
  // The edited attributes
  attributes: DataListEditedRowsAttributes;
  // The tree grid row if we are editing a tree-grid
  treeRow?: any;
}

export interface DataListEditedRowsAttributes {
  [key: string]: Attribute;
}
<div class="nm-dataList__header">
  <mat-form-field
    *ngIf="globalFilterInput && !hideFilters"
    class="nm-dataList__headerInput"
  >
    <input
      matInput
      type="text"
      [placeholder]="'placeholder.free.text.search' | translate"
      [(ngModel)]="globalFilterValue"
      (input)="onFilterValueChange()"
      [nmAutofocus]="configuration.focusFreeTextSearch || autoFocus"
    />

    <button
      mat-icon-button
      *ngIf="globalFilterValue"
      color="primary"
      class="nm-dataList__headerClearButton"
      matSuffix
      aria-label="Clear"
      (click)="clearGlobalFilter()"
    >
      <mat-icon>close</mat-icon>
    </button>
  </mat-form-field>

  <button
    *ngIf="configuration.removeAllFiltersButton && !hideFilters"
    class="nm-dataList__headerButton"
    [disabled]="
      grid.filteringExpressionsTree.filteringOperands.length === 0 &&
      grid.sortingExpressions.length === 0
    "
    mat-icon-button
    [pTooltip]="'placeholder.reset.config.table' | translate"
    [showDelay]="300"
    color="primary"
    (click)="clearAllFiltersAndSorting()"
  >
    <mat-icon>settings_backup_restore</mat-icon>
  </button>

  <ng-container
    *ngIf="listService.recommendedAttributes | async as recommendedAttributes"
  >
    <a
      *ngIf="recommendedAttributes != null && recommendedAttributes.count !== 0"
      (click)="takeRecommendedAttributes(recommendedAttributes)"
    >
      {{
        "label.take.recommended.attributes"
          | translate: { count: recommendedAttributes.count }
      }}
    </a>
  </ng-container>

  <div *ngIf="configuration.headerComponents">
    <nm-container
      *ngFor="
        let component of configuration.headerComponents.configuration
          ?.components
      "
      [configuration]="component | widgetFor: configuration"
      [parent]="widgetId"
      [id]="component"
    ></nm-container>
  </div>

  <div
    *ngIf="!configuration.removeHeaderAdditionalSpace"
    style="flex-grow: 1"
  ></div>

  <mat-slider
    type="range"
    min="1"
    max="5"
    *ngIf="selectedViewMode && selectedViewMode.identifier !== 'listView'"
    [pTooltip]="'placeholder.image.size' | translate"
    [showDelay]="300"
    [(ngModel)]="slidevalue"
    (change)="slideChange.next(slidevalue)"
  >
  </mat-slider>

  <mat-form-field
    style="z-index: 12"
    class="nm-dataList__headerSelection"
    *ngIf="
      dataTypeModeChannel.value === 'choose' && availableDataTypes.length > 0
    "
  >
    <mat-label>{{ "placeholder.dataType" | translate }}</mat-label>
    <nm-combo
      [options]="availableDataTypes"
      [(value)]="selectedDataType"
      (valueChange)="onDataTypeChange()"
      [clearable]="false"
      [showHeader]="availableDataTypes.length > 2"
    >
      <ng-template nmComboOption let-option>
        {{ option | translate }}
      </ng-template>

      <ng-template nmComboTrigger let-api let-selection="selection">
        {{ selection[0] | translate }}
      </ng-template>
    </nm-combo>
  </mat-form-field>

  <mat-slide-toggle
    *ngIf="configuration.enableToggleButton"
    tooltipPosition="bottom"
    (change)="toggleMode($event)"
    >{{ toggleButtonLabel | translate }}</mat-slide-toggle
  >

  <button
    *ngIf="isListMode && attributeUrl"
    class="nm-dataList__headerButton"
    mat-stroked-button
    (click)="editShownAttributes()"
    (keydown.enter)="$event.stopPropagation()"
  >
    {{ "button.attributes" | translate }}
  </button>

  <button
    *ngIf="configuration.reloadButton"
    class="nm-dataList__headerButton"
    mat-icon-button
    [pTooltip]="'label.refresh' | translate"
    [showDelay]="300"
    color="primary"
    (click)="doRefresh()"
    [disabled]="!(listService.data | async)"
  >
    <mat-icon class="nm-grey-button">refresh</mat-icon>
  </button>

  <mat-form-field
    class="nm-dataList__headerSelection"
    *ngIf="configuration.viewModeSelection"
  >
    <mat-label>{{ "placeholder.viewMode" | translate }}</mat-label>
    <nm-combo
      [options]="viewModeOptions"
      displayKey="description"
      [(value)]="selectedViewMode"
      (valueChange)="onViewModeChange()"
      [clearable]="false"
      [showHeader]="viewModeOptions.length > 2"
    >
      <ng-template nmComboOption let-option>
        <ng-container *ngIf="option.icon">
          <mat-icon color="primary">{{ option.icon }}</mat-icon
          >&nbsp;
        </ng-container>
        {{ option.description | translate }}
      </ng-template>

      <ng-template nmComboTrigger let-api let-selection="selection">
        <ng-container *ngIf="selection[0] as option">
          <span class="nm-dataList__viewMode--trigger">
            <ng-container *ngIf="option.icon"
              ><mat-icon color="primary">{{ option.icon }}</mat-icon
              >&nbsp;</ng-container
            >
            {{ option.description | translate }}
          </span>
        </ng-container>
      </ng-template>
    </nm-combo>
  </mat-form-field>

  <div
    *ngIf="
      configuration.visibleDataColumnsSelection &&
      selectedDataType === 'attributes'
    "
    class="nm-dataList__headerSelection_icon"
  >
    <nm-combo
      matTooltip="{{ 'label.hidden.columns' | translate }}"
      [options]="columns.dataColumnsConfigurableVisibility | async"
      [valueKey]="'field'"
      [displayKey]="'header' | translate"
      [filterPlaceholder]="'placeholder.search' | translate"
      [multiple]="true"
      [value]="visibleDataColumns"
      [clearable]="false"
      [iconMode]="true"
      (valueChange)="onDataColumnsChange($event)"
    >
      <ng-template nmComboOption let-option>
        {{ option.header | translate }}
      </ng-template>
      <ng-template nmComboTrigger let-option>
        <mat-icon
          color="primary"
          matBadge="{{
            (columns.dataColumnsConfigurableVisibility | async).length -
              visibleDataColumns.length
          }}"
          >view_column
        </mat-icon>
      </ng-template>
    </nm-combo>
  </div>
</div>

<ng-container
  #tileViewTemplate
  *ngIf="selectedViewMode && selectedViewMode.identifier !== 'listView'"
>
  <nm-data-list-tile-view
    [listService]="listService"
    [data]="currentDataChannel"
    [slideChange]="slideChange"
    [columns]="columns.columns"
    [grid]="grid"
    [frameHeight]="frameHeight"
    [tileRedirectLink]="tileRedirectLink"
    [overrideTileClickEvent]="overrideTileClickEvent"
    (click)="tileClicked($event)"
    [identifierField]="tileIdentifierField"
  >
  </nm-data-list-tile-view>
</ng-container>

<div
  class="nm-dataList__content igx-data-content {{ filterMode }}"
  [ngStyle]="{ height: tableHeight }"
  [ngClass]="{
    'u-hidden': selectedViewMode && selectedViewMode.identifier !== 'listView'
  }"
  [class.removeColumnHeader]="removeColumnHeader"
>
  <igx-grid
    nm-paste-handler
    [pasteGrid]="table"
    (onDataProcessed)="dataPasted($event)"
    [data]="listService.data | async"
    [height]="tableGridHeight"
    [width]="tableGridWidth"
    [hideRowSelectors]="!rowSelectable"
    [rowSelection]="rowSelectionMode"
    (cellClick)="onCellClick($event)"
    [columnHiding]="true"
    [displayDensity]="density"
    [primaryKey]="_primaryKey"
    [autoGenerate]="false"
    (dataPreLoad)="listService.processData(false)"
    [allowFiltering]="true"
    [rowEditable]="configuration.rowEditable"
    (rowEdit)="onRowEdit($event)"
    (rowEditEnter)="onRowEditEnter()"
    (rowEditExit)="onRowEditCancel()"
    (cellEdit)="onCellEdit($event)"
    (cellEditEnter)="onCellEditEnter($event)"
    (cellEditExit)="onCellEditExit()"
    (sortingDone)="processDataOnChange($event, true)"
    (filteringDone)="onFilteringDone()"
    (rowSelected)="onRowSelection($event)"
    (rangeSelected)="onRangeSelection($event)"
    [filterMode]="filterMode"
    [class.showFilterRow]="showFilterRow"
    [class.isTileView]="!isListMode"
    [groupingExpressions]="groupingExpressions"
    [sortingExpressions]="sortingExpressions"
    (columnVisibilityChanged)="onVisibilityChanged($event)"
    (contextMenu)="openContextmenu($event)"
    [tableIdentifier]="
      (contextIdentifierChannel | async)
        ? (contextIdentifierChannel | async)
        : (configuration.identifier
            ? configuration.identifier
            : configuration.title) +
          (selectedDataType ? '-' + selectedDataType : '')
    "
    [clipboardOptions]="clipboardOptions"
    [pinning]="pinningConfig"
    [rowDraggable]="configuration.enableRowDragging"
    (rowDragStart)="onRowDragStart($event)"
    (dropped)="onDrop($event)"
    (columnOrderChanged)="columnOrderChanged($event)"
    (storingEnabled)="(storingEnabled)"
    (columnInit)="columnInit($event)"
    [locale]="listService.selectedLocale || currentLocaleService.currentLocale"
    igxDrop
    [dataList]="this"
    (filteringExpressionsTreeChange)="!isEagerLoading ? grid.navigateTo(0) : ''"
    statefulDataList
    #table
  >
    <ng-template igxDragIndicatorIcon>
      <igx-icon>drag_handle</igx-icon>
    </ng-template>

    <ng-template igxHeadSelector let-headContext *ngIf="!isEagerLoading">
      <div
        class="igx-grid__cbx-padding"
        style="height: 100%"
        (click)="$event.stopPropagation()"
      >
        <igx-checkbox
          [checked]="selectAllCheckbox"
          [indeterminate]="selectAllCheckbox === null"
          (change)="onHeaderSelectorClick($event)"
        >
        </igx-checkbox>
      </div>
    </ng-template>
    <igx-column
      *ngFor="
        let nmColumn of (showActionsInTableColumn
          ? columns.columns
          : columns.dataColumns
        )
          | async
          | nmDataListColumnSettings
            : this
            : (columns.columnOrder | async)
            : visibleDataColumns
            : showAllColumns;
        trackBy: trackColumns
      "
      [field]="nmColumn.field"
      [sortable]="nmColumn.sortable"
      [filterable]="nmColumn.filter"
      [header]="
        (nmColumn.dynamicHeader
          ? listService.dataType + '-' + nmColumn.header
          : nmColumn.header
        ) | translate
      "
      [width]="nmColumn.width ? nmColumn.width : '200px'"
      [minWidth]="nmColumn.minWidth ? nmColumn.minWidth : '0px'"
      [maxWidth]="nmColumn.maxWidth ? nmColumn.maxWidth : '10000px'"
      [pinned]="isListMode ? nmColumn.pinned : false"
      [hidden]="nmColumn.hidden"
      [editable]="true === nmColumn.editable"
      [groupable]="nmColumn.groupable"
      [disableHiding]="nmColumn.disableHiding ? nmColumn.disableHiding : true"
      [movable]="isListMode ? true : false"
      [resizable]="isListMode ? true : false"
      [sortStrategy]="nmColumn.settings.sortStrategy"
      [groupingComparer]="nmColumn.settings.groupingComparer"
      [cellClasses]="nmColumn.settings.cellClasses"
      [headerClasses]="nmColumn.settings.headerClasses"
      [dataType]="nmColumn.dataType"
      [additionalTemplateContext]="nmColumn"
      [headerTemplate]="
        filterMode === 'inlineFilter' || nmColumn.tooltip
          ? columnHeaderTemplate
          : null
      "
      [cellEditorTemplate]="columnEditorTemplate"
      [cellTemplate]="columnCellTemplate"
    >
    </igx-column>
    <ng-container *ngIf="!showActionsInTableColumn">
      <igx-action-strip
        *ngIf="!rowPinningEnabled; else rowPinningEnabledTemplate"
        #actionStrip
      >
        <ng-container
          *ngTemplateOutlet="
            !this.cellEditModeActive ? actionStripTemplate : undefined;
            context: { actionStrip: actionStrip }
          "
        >
        </ng-container>
      </igx-action-strip>

      <ng-template #rowPinningEnabledTemplate>
        <igx-action-strip *ngIf="rowPinningEnabled" #actionStrip>
          <ng-container
            *ngTemplateOutlet="
              actionStripTemplate;
              context: { actionStrip: actionStrip }
            "
          >
          </ng-container>
          <igx-grid-pinning-actions></igx-grid-pinning-actions>
        </igx-action-strip>
      </ng-template>
    </ng-container>
  </igx-grid>
</div>

<div
  *ngIf="childComponentMenu.menuObs | async as menu"
  style="position: fixed"
  #menuTrigger="matMenuTrigger"
  [style.left]="contextMenuCoordinates.x"
  [style.top]="contextMenuCoordinates.y"
  [matMenuTriggerFor]="menu"
></div>
<nm-grid-contextmenu
  [cell]="contextMenuCoordinates.cell"
  [grid]="this"
  [column]="contextMenuColumn"
  [selected-items]="selectedItems"
  [total]="listService.totalSubject"
  [link]="listService.linkWithoutPaging"
  [configuration]="configuration"
  [api]="apiEmitter | async"
  (closeContextMenu)="closeContextMenu()"
  (export)="onExport($event)"
>
</nm-grid-contextmenu>

<ng-template #groupRowTemplate igxGroupByRow let-groupRow>
  <nm-data-list-group-component
    [grid]="grid"
    [record]="groupRow"
    (groupSelectionChange)="onRowSelection($event)"
  ></nm-data-list-group-component>
</ng-template>

<ng-template #actionStripTemplate let-actionStrip="actionStrip">
  <nm-list-cell-action-strip
    [actionColumns]="columns.actionColumns | async"
    [rowContext]="actionStrip.context"
    [dataType]="listService.dataType"
  >
  </nm-list-cell-action-strip>
</ng-template>

<div igxOverlayOutlet></div>

<ng-template #columnHeaderTemplate let-column>
  <ng-container *ngIf="filterMode === 'inlineFilter'; else showTooltip">
    <div
      class="title-inner"
      [attr.draggable]="false"
      [ngClass]="column.additionalTemplateContext.settings.columnHeaderClasses"
    >
      <span
        *ngIf="!column.additionalTemplateContext.filter"
        class="nm-title-container"
      >
        {{
          (column.additionalTemplateContext.dynamicHeader
            ? listService.dataType +
              "-" +
              column.additionalTemplateContext.header
            : column.additionalTemplateContext.header
          ) | translate
        }}
      </span>

      <mat-form-field
        *ngIf="column.additionalTemplateContext.filter"
        class="nm-list-column-search"
        [attr.draggable]="false"
      >
        <input
          [attr.draggable]="false"
          #inputBox
          [ngClass]="column.field"
          matInput
          type="text"
          (click)="stopPropagation($event, column.field)"
          (keydown)="$event.stopImmediatePropagation()"
          [placeholder]="
            (column.additionalTemplateContext.dynamicHeader
              ? listService.dataType +
                '-' +
                column.additionalTemplateContext.header
              : column.additionalTemplateContext.header
            ) | translate
          "
          [(ngModel)]="dataListStateDirective.columnFilterInput[column.field]"
          (input)="
            onColumnFilterInput(
              dataListStateDirective.columnFilterInput[column.field],
              column
            )
          "
        />

        <button
          (click)="$event.stopPropagation()"
          [attr.draggable]="false"
          mat-button
          *ngIf="dataListStateDirective.columnFilterInput[column.field]"
          matSuffix
          mat-icon-button
          aria-label="Clear"
          (click)="
            clearColumnFilter(
              dataListStateDirective.columnFilterInput[column.field],
              column
            )
          "
        >
          <mat-icon [attr.draggable]="false">close</mat-icon>
        </button>
      </mat-form-field>

      <mat-icon
        *ngIf="!column.additionalTemplateContext.hidePin"
        class="nm-table-head-icon nm-table-pin fa fa fa-thumb-tack fade-in"
        [class.pinned]="column.pinned"
        [attr.draggable]="false"
        (click)="column.pinned = !column.pinned"
      ></mat-icon>
    </div>
  </ng-container>

  <ng-template #showTooltip>
    <span
      pTooltip="{{ column.additionalTemplateContext.tooltip | translate }}"
      >{{ column.header }}</span
    >
  </ng-template>
</ng-template>

<ng-template #columnEditorTemplate let-val let-cell="cell">
  <nm-list-cell-edit
    [column]="cell.column?.additionalTemplateContext"
    [dataType]="listService.dataType"
    [cell]="cell"
    [primaryKey]="_primaryKey"
    [density]="density"
    [validation]="{ grid: this, config: configuration }"
    (editableCell)="editableCell.emit($event)"
    [attr.data-rowindex]="cell.row.index"
  >
  </nm-list-cell-edit>
</ng-template>

<ng-template #columnCellTemplate let-val let-cell="cell">
  <nm-list-cell
    *ngIf="
      cell?.column &&
      !cell.row.rowData.cache &&
      !cell.column?.additionalTemplateContext.draggable
    "
    [source]="
      cell.row.rowData[cell.column?.additionalTemplateContext.settings.source]
    "
    [column]="cell.column?.additionalTemplateContext"
    [row]="cell.row.rowData"
    [value]="cell.value"
    [highlightReadOnly]="
      cell.column?.additionalTemplateContext.settings.highlightReadOnly
    "
    [cell]="cell"
    [density]="density"
    [ignoreSeconds]="configuration.ignoreSeconds"
    [chipColors]="configuration.chipColors"
    [columnSelector]="columnSelector"
    [attr.data-rowindex]="cell.row.index"
    [dataType]="listService.dataType"
    igxDrop
    (dropped)="
      onItemDropped($event, cell, cell.column?.additionalTemplateContext)
    "
  >
  </nm-list-cell>
  <nm-list-cell
    *ngIf="
      cell?.column &&
      !cell.row.rowData.cache &&
      cell.column?.additionalTemplateContext.draggable
    "
    [source]="
      cell.row.rowData[cell.column?.additionalTemplateContext.settings.source]
    "
    [column]="cell.column?.additionalTemplateContext"
    [value]="cell.value"
    [dataType]="listService.dataType"
    [row]="cell.row.rowData"
    [highlightReadOnly]="
      cell.column?.additionalTemplateContext.settings.highlightReadOnly
    "
    [cell]="cell"
    [density]="density"
    [ignoreSeconds]="configuration.ignoreSeconds"
    [chipColors]="configuration.chipColors"
    [columnSelector]="columnSelector"
    [igxDrag]="{
      type: 'data-list-row',
      source: cell.row.rowData,
      column: cell.column?.additionalTemplateContext
    }"
    [attr.data-rowindex]="cell.row.index"
    igxDrop
    (dropped)="
      onItemDropped($event, cell, cell.column?.additionalTemplateContext)
    "
    igxDragHandle
  >
  </nm-list-cell>
  <nm-content-preview
    *ngIf="cell.row.rowData.cache"
    [min-width]="cell.column?.additionalTemplateContext.minWidth"
    [max-width]="
      cell.column?.additionalTemplateContext.width ||
      cell.column?.additionalTemplateContext.maxWidth
    "
  >
  </nm-content-preview>
</ng-template>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""