File

src/app/shared/widgets/data-list/data-list-columns.service.ts

Index

Widget inputs
Widget outputs
Properties
Methods

Constructor

constructor(_configuration: DataListConfiguration, appService: AppService, translateService: TranslateService)
Parameters :
Name Type Optional
_configuration DataListConfiguration no
appService AppService no
translateService TranslateService no

Properties

Private _columnMap
_columnMap: object
Type : object
Default value : {}
Private _columnObservable
_columnObservable: Observable<Column[]>
Type : Observable<Column[]>
Private _columns
_columns: BehaviorSubject<Column[]>
Type : BehaviorSubject<Column[]>
Default value : new BehaviorSubject([])
Private _dynamicColumnObservable
_dynamicColumnObservable: Observable<Column[]>
Type : Observable<Column[]>
Private _dynamicColumns
_dynamicColumns: BehaviorSubject<Column[]>
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: Observable<Column[]>
Type : Observable<Column[]>
Public columnOrder
columnOrder:
Default value : new BehaviorSubject<string[]>([])
Public columns
columns: Observable<Column[]>
Type : Observable<Column[]>
Public dataColumns
dataColumns: Observable<Column[]>
Type : Observable<Column[]>
Public dataColumnsConfigurableVisibility
dataColumnsConfigurableVisibility: Observable<Column[]>
Type : Observable<Column[]>
Public dynamicColumns
dynamicColumns: Observable<Column[]>
Type : Observable<Column[]>
Public dynamicColumnsFromData
dynamicColumnsFromData: boolean | null
Type : boolean | null
Default value : null
Public dynamicColumnsMode
dynamicColumnsMode: "concat" | "unique"
Type : "concat" | "unique"
Public headerGroups
headerGroups: Observable<DataListHeaderGroup[]>
Type : Observable<DataListHeaderGroup[]>
Public order
order:
Public shownAttributes
shownAttributes: []
Type : []
Default value : []
Public summaries
summaries: ColumnSummaries[]
Type : ColumnSummaries[]
Default value : []

Methods

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 :
Name Type Optional Default value
columns any[] no
fromBackend no false
Returns : void
Public updateDynamicColumnsHeaders
updateDynamicColumnsHeaders(locale: )

Updates the dynamic columns headers that are shown for the table based on the given locale.

Parameters :
Name Optional
locale no
Returns : void
Public updateGroups
updateGroups(groups: DataListHeaderGroup[], fromBackend: )
Parameters :
Name Type Optional Default value
groups DataListHeaderGroup[] no
fromBackend no false
Returns : void

Accessors

dataType
setdataType(value: )
Parameters :
Name Optional
value no
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();
  }
}

results matching ""

    No results matching ""