src/app/shared/widgets/data-list/data-list-columns.service.ts
Widget inputs |
Widget outputs |
Properties |
|
Methods |
|
constructor(_configuration: DataListConfiguration, appService: AppService, translateService: TranslateService)
|
||||||||||||
Parameters :
|
Private _columnMap |
_columnMap:
|
Type : object
|
Default value : {}
|
Private _columnObservable |
_columnObservable:
|
Type : Observable<Column[]>
|
Private _columns |
_columns:
|
Type : BehaviorSubject<Column[]>
|
Default value : new BehaviorSubject([])
|
Private _dynamicColumnObservable |
_dynamicColumnObservable:
|
Type : Observable<Column[]>
|
Private _dynamicColumns |
_dynamicColumns:
|
Type : BehaviorSubject<Column[]>
|
Default value : new BehaviorSubject([])
|
Private _dynamicHeaderGroups |
_dynamicHeaderGroups:
|
Default value : new BehaviorSubject<DataListHeaderGroup[]>([])
|
Private _headerGroups |
_headerGroups:
|
Default value : new BehaviorSubject<DataListHeaderGroup[]>([])
|
Private _unsubscribe |
_unsubscribe:
|
Default value : NgUnsubscribe.create()
|
Public actionColumns |
actionColumns:
|
Type : Observable<Column[]>
|
Public columnOrder |
columnOrder:
|
Default value : new BehaviorSubject<string[]>([])
|
Public columns |
columns:
|
Type : Observable<Column[]>
|
Public dataColumns |
dataColumns:
|
Type : Observable<Column[]>
|
Public dataColumnsConfigurableVisibility |
dataColumnsConfigurableVisibility:
|
Type : Observable<Column[]>
|
Public dynamicColumns |
dynamicColumns:
|
Type : Observable<Column[]>
|
Public dynamicColumnsFromData |
dynamicColumnsFromData:
|
Type : boolean | null
|
Default value : null
|
Public dynamicColumnsMode |
dynamicColumnsMode:
|
Type : "concat" | "unique"
|
Public headerGroups |
headerGroups:
|
Type : Observable<DataListHeaderGroup[]>
|
Public order |
order:
|
Public shownAttributes |
shownAttributes:
|
Type : []
|
Default value : []
|
Public summaries |
summaries:
|
Type : ColumnSummaries[]
|
Default value : []
|
Public autosizableColumns |
autosizableColumns()
|
Return the list of autosizable columns
Returns :
string[]
|
destroy |
destroy()
|
Returns :
void
|
Public updateColumns | ||||||||||||
updateColumns(columns: any[], fromBackend: )
|
||||||||||||
Updates the columns that are shown for the table. If this table is in dynamicColumnsFromData mode only changes with fromBackend = true will be processed
Parameters :
Returns :
void
|
Public updateDynamicColumnsHeaders | ||||
updateDynamicColumnsHeaders(locale: )
|
||||
Updates the dynamic columns headers that are shown for the table based on the given locale.
Parameters :
Returns :
void
|
Public updateGroups | ||||||||||||
updateGroups(groups: DataListHeaderGroup[], fromBackend: )
|
||||||||||||
Parameters :
Returns :
void
|
dataType | ||||
setdataType(value: )
|
||||
Parameters :
Returns :
void
|
displayedAttributes |
getdisplayedAttributes()
|
import { BehaviorSubject, combineLatest, Observable, Subject } from "rxjs";
import {
Column,
DataListConfiguration,
DataListHeaderGroup,
} from "../interfaces/list.interfaces";
import {
map,
filter,
shareReplay,
takeUntil,
distinctUntilChanged,
} from "rxjs/operators";
import { Injectable, OnDestroy } from "@angular/core";
import { NgUnsubscribe } from "../../ng-unsubscribe";
import { AppService } from "../configuration/app.service";
import { WidgetConfig } from "../widget.configuration";
import {
ColumnSummaries,
ExtendedSummary,
} from "./data-list-summaries.component";
import { Attributes } from "../../components/edit-attribute";
import * as _ from "lodash";
import { TranslateService } from "@ngx-translate/core";
export class DataListColumnsService {
private _unsubscribe = NgUnsubscribe.create();
private _columnMap = {};
private _dynamicColumns: BehaviorSubject<Column[]> = new BehaviorSubject([]);
private _dynamicColumnObservable: Observable<Column[]>;
private _columns: BehaviorSubject<Column[]> = new BehaviorSubject([]);
private _columnObservable: Observable<Column[]>;
private _headerGroups = new BehaviorSubject<DataListHeaderGroup[]>([]);
private _dynamicHeaderGroups = new BehaviorSubject<DataListHeaderGroup[]>([]);
public headerGroups: Observable<DataListHeaderGroup[]>;
public shownAttributes = [];
public dynamicColumnsFromData: boolean | null = null;
public dynamicColumnsMode: "concat" | "unique";
public summaries: ColumnSummaries[] = [];
public dynamicColumns: Observable<Column[]>;
public columns: Observable<Column[]>;
public dataColumns: Observable<Column[]>;
public actionColumns: Observable<Column[]>;
public dataColumnsConfigurableVisibility: Observable<Column[]>;
public columnOrder = new BehaviorSubject<string[]>([]);
public order;
constructor(
private _configuration: DataListConfiguration,
private appService: AppService,
private translateService: TranslateService
) {
this.headerGroups = combineLatest(
this._headerGroups,
this._dynamicHeaderGroups
).pipe(
map(([a, b]) => a.concat(...b)),
map((groups) => groups.sort((a, b) => a.order || 0 - b.order || 0))
);
this.dynamicColumnsFromData = this._configuration.dynamicColumnsFromData;
this.dynamicColumnsMode =
this._configuration.dynamicColumnsMode || "concat";
this._configuration.columns.map(function (entry) {
entry.disableHiding = true;
return entry;
});
this._columns.next(this._configuration.columns);
this._dynamicColumnObservable = this._dynamicColumns
.asObservable()
.pipe(takeUntil(this._unsubscribe));
this._columnObservable = combineLatest(
this._columns.asObservable(),
this._dynamicColumnObservable
).pipe(
map((configs) => {
if (this.dynamicColumnsMode === "concat") {
return [].concat(...configs);
}
if (this.dynamicColumnsMode === "unique") {
let known = new Set<string>();
let columns: Column[] = [];
configs.forEach((config) => {
config.forEach((column) => {
let field = column.field;
if (field === "") {
columns.push(column);
return;
}
if (known.has(field)) {
return;
}
columns.push(column);
known.add(field);
});
});
return columns;
}
}),
map((columns) =>
columns.map((column: Column) => {
let field: string = column.field;
let isAttribute =
field?.endsWith("#source") ||
column.type === "attribute" ||
(column.type == null &&
this.shownAttributes.find(
(attribute) => attribute.identifier === field
) != null);
if (
isAttribute &&
column.editable &&
!field.endsWith("#source") &&
!field.endsWith("#value")
) {
console.warn(
"Column definition of type 'attribute' should end with '#source'!",
column
);
}
if (isAttribute) {
field = Attributes.toValueField(column.field);
}
let key = `${field}#${column.type}`;
if (!this._columnMap.hasOwnProperty(key)) {
this._columnMap[key] = Object.assign(column, { field });
} else {
this._columnMap[key] = Object.assign(
{},
this._columnMap[key],
column,
{ field }
);
}
if (this._configuration.density === "comfortable") {
let maxWidth =
typeof column.maxWidth === "string"
? parseInt(column.maxWidth)
: column.maxWidth;
if (maxWidth < 100) {
column.maxWidth = "100px";
column.minWidth = "100px";
column.width = "100px";
}
}
if (column.hasSummary) {
if (column.customSummary) {
this.summaries.push({
fieldName: column.field,
customSummary: ExtendedSummary,
});
} else {
this.summaries.push({
fieldName: column.field,
});
}
}
return this._columnMap[key];
})
),
map((columns) => {
return columns.sort((a, b) => {
return (a.order || 1000) - (b.order || 1000);
});
}),
distinctUntilChanged((x, y) => {
if (!Array.isArray(x) || !Array.isArray(y)) {
return false;
}
if (x.length !== y.length) {
return false;
}
for (let i = 0; i < x.length; i++) {
if (!_.isEqual(x[i], y[i])) {
return false;
}
}
return true;
}),
takeUntil(this._unsubscribe),
shareReplay(1)
);
this.dynamicColumns = this._dynamicColumnObservable;
this.columns = this._columnObservable;
this.dataColumns = this._columnObservable.pipe(
map((columns) => {
return columns.filter(
(column) =>
!(
column.type === "hal-actions" ||
column.type === "actions-and-interactions" ||
column.type === "interactions"
)
);
})
);
this.actionColumns = this._columnObservable.pipe(
map((columns) => {
return columns.filter(
(column) =>
column.type === "hal-actions" ||
column.type === "actions-and-interactions" ||
column.type === "interactions"
);
})
);
this.dataColumnsConfigurableVisibility = this.dataColumns
.pipe(
map((columns) => {
return columns.filter((column) => column.visibilityConfigurable);
})
)
.pipe(
map((groups) =>
groups.sort((a, b) =>
translateService.instant(a.header) <
translateService.instant(b.header)
? -1
: 1
)
)
);
}
public set dataType(value) {
if (this._configuration.dataTypeColumns) {
const columns = this._configuration.dataTypeColumns[value];
const newColumns = [...this._configuration.columns];
if (columns) {
newColumns.unshift(...columns);
}
this._columns.next(newColumns);
}
}
get displayedAttributes(): string[] {
return this.shownAttributes.map((attribute) => attribute.identifier);
// return this._dynamicColumns.getValue()
// .filter(column => !column.hidden)
// .map(column => column.field);
}
public updateGroups(groups: DataListHeaderGroup[], fromBackend = false) {
this._dynamicHeaderGroups.next(groups);
}
/**
* Updates the columns that are shown for the table. If this table is in dynamicColumnsFromData mode only changes with fromBackend = true will be processed
*/
public updateColumns(columns: any[], fromBackend = false) {
if (this.dynamicColumnsFromData && !fromBackend) {
return;
}
let dynamicColumns: Column[] = this._dynamicColumns.getValue() || [];
dynamicColumns = dynamicColumns.filter(
(column) =>
columns.findIndex(
(attribute) =>
attribute.identifier == column.field &&
attribute.description == column.header
) >= 0
);
//Add all dynamic columns for attributes that weren't present in the list
columns
.filter(
(attribute) =>
dynamicColumns.findIndex(
(column) => column.field == attribute.identifier
) < 0
)
.forEach((columnResource) => {
let template;
const templateName = columnResource.template
? columnResource.template
: "attributes";
if (this._configuration.columnTemplates) {
template = this._configuration.columnTemplates[templateName];
if (!template) {
template = this._configuration.columnTemplates["default"];
}
}
if (!template) {
template = {
width: 200,
sortable: true,
filter: true,
disableHiding: false,
};
}
const field =
template.type === "attribute"
? Attributes.toValueField(columnResource.identifier)
: columnResource.identifier;
const widgetId = columnResource.renderWidget
? "data-list-" + columnResource.renderWidget
: template.widget;
// lookup column in "shown attributes" to check, if we know the attribute's data type
const attribute = this.shownAttributes.find(
(attr) => attr.identifier == columnResource.identifier
);
const dataType = template.dataType
? template.dataType
: Attributes.dataTypeFromAttribute(
attribute?.type || attribute?.dataType
? attribute
: columnResource
);
const columnRef: Column = Object.assign({}, template, {
field,
mandatory: columnResource.mandatory,
header: columnResource.description,
disableHiding: false,
parent: columnResource.parent,
widget: widgetId,
tooltip: columnResource.hasOwnProperty("tooltip")
? columnResource.tooltip
: "",
locales: columnResource.locales,
// set order or fallback to template order
order: columnResource.order || template.order,
dataType,
});
if (columnResource.articleType) {
columnRef.articleType = columnResource.articleType;
}
if (columnResource.renderWidget) {
columnRef.type = "widget";
if (!this.appService.hasWidget(widgetId)) {
const config: WidgetConfig = {
id: widgetId,
component: columnResource.renderWidget,
configuration: {},
};
this.appService.registerWidget(config);
}
}
dynamicColumns.push(columnRef);
});
dynamicColumns.sort((a, b) => {
let attributes = this.shownAttributes.map(
(attribute) => attribute.identifier
);
let aField = Attributes.fromField(a.field);
let bField = Attributes.fromField(b.field);
return attributes.indexOf(aField) - attributes.indexOf(bField);
});
this._dynamicColumns.next(dynamicColumns);
}
/**
* Updates the dynamic columns headers that are shown for the table based on the given locale.
*/
public updateDynamicColumnsHeaders(locale) {
this._dynamicColumns.getValue().forEach((column) => {
if (column.locales) {
const locales = column.locales;
if (locales[locale]) {
column.header = locales[locale];
}
}
});
this._dynamicColumns.next(this._dynamicColumns.value);
}
/**
* Return the list of autosizable columns
*/
public autosizableColumns(): string[] {
const autosizableColumns = this._columns.value.filter(
(column) => column.field && column.autosize
);
const autosizableDynamicColumns = this._dynamicColumns.value.filter(
(column) => column.autosize
);
return [...autosizableColumns, ...autosizableDynamicColumns].map(
(column) => column.field
);
}
destroy(): void {
this._unsubscribe.destroy();
}
}