File

src/app/shared/widgets/select/select.component.ts

Index

Properties

Properties

add-all-option
add-all-option: boolean
Type : boolean
Optional

A flag to add 'ALL' as an option.

addLabel
addLabel: boolean
Type : boolean
Optional

Add or Hide label. @default(false)

autofocus
autofocus: boolean
Type : boolean
Optional

Auto focus field.

clearOptionsOnReset
clearOptionsOnReset: boolean
Type : boolean
Optional

Enable or Disable clear options selected on reset. @default(false)

cssClass
cssClass: string
Type : string
Optional

css class that should be applied for the selection.

customValueMode
customValueMode: boolean
Type : boolean
Optional

Enable or Disable custom mode. @default(false)

data-from-stream
data-from-stream: boolean
Type : boolean
Optional

Allow to fetch data from a stream, if true then data are fetched from input channel. @default(false)

enableGroupSelection
enableGroupSelection: boolean
Type : boolean
Optional

Enable or disable group selection. @default(false)

enableSelectSearch
enableSelectSearch: boolean
Type : boolean
Optional

Allow select search @default(true)

floatLabel
floatLabel: string
Type : string
Optional

Whether the label for fields should by default float.

grouped
grouped: boolean
Type : boolean
Optional

Allow group selection. @default(false)

infoText
infoText: string
Type : string
Optional

Text of the info-dialog. Should be a translation-key

infoTitle
infoTitle: string
Type : string
Optional

Title of the info-dialog. Should be a translation-key

isMandatory
isMandatory: boolean
Type : boolean
Optional

A flag that controls if the selection is mandatory or not. @default(false)

labelName
labelName: string
Type : string
Optional

The label name.

local-storage-key
local-storage-key: string
Type : string

Storage key to keep the selected option.

local-storage-key-type
local-storage-key-type: string
Type : string
Optional

Storage key type to keep the selected option.

multi
multi: boolean
Type : boolean
Optional

Allow multiple selection. @default(false)

placeholder
placeholder: string
Type : string
Optional

The placeholder for the value.

remote-data-add-empty-option
remote-data-add-empty-option: boolean
Type : boolean
Optional

A flag to add empty option.

remote-data-badge
remote-data-badge: string
Type : string
Optional

Creating a small circle, typically containing a number or other short set of characters.

remote-data-dataType
remote-data-dataType: any
Type : any
Optional

The datatype of the values that will be selected.

remote-data-measurementUnit
remote-data-measurementUnit: string
Type : string
Optional

Extract value of UOM.

remote-data-prompt
remote-data-prompt: string
Type : string
Optional

The value that is shown to the user on selection.

remote-data-url
remote-data-url: string
Type : string
Optional

Fetch data of the select from a url.

remote-data-value
remote-data-value: string
Type : string
Optional

The represented object value of the selection on emit.

required
required: boolean
Type : boolean
Optional

Enable or Disable required selection. @default(false)

selectWidth
selectWidth: string
Type : string
Optional

Sets width of select

shouldLabelFloat
shouldLabelFloat: boolean
Type : boolean
Optional

Whether the label should try to float or not. @default(false)

title
title: string
Type : string
Optional

Title of component.

values
values: any[]
Type : any[]
Optional

Values to be selected.

import {
  BehaviorSubject,
  combineLatest as observableCombineLatest,
  ReplaySubject,
  Subject,
  Subscription,
} from "rxjs";

import { map, mergeMap, takeUntil, filter } from "rxjs/operators";
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  OnDestroy,
  ViewChild,
} from "@angular/core";
import { WidgetframeService } from "../widgetframe/widgetframe.service";
import { getOrDefault, WidgetConfig } from "../widget.configuration";
import {
  WidgetComponent,
  WidgetConfiguration,
  WidgetConfigure,
  WidgetId,
  WidgetInput,
  WidgetOutput,
} from "../widget.metadata";
import { NgUnsubscribe } from "../../ng-unsubscribe";
import { TranslateService } from "@ngx-translate/core";
import { ConfirmationDialogComponent } from "../../components/dialog/confirmationDialog.component";
import { FormControl } from "@angular/forms";

import * as uriTemplates_ from "uri-templates";
import {
  LocalStorageEntry,
  LocalStorageService,
} from "../../components/local-storage/local-storage.service";
import {
  DeletionMode,
  Scope,
} from "../../components/local-storage/local-storage-constants";
import { ProgressbarService } from "../../components/progressbar/progressbar.service";
import { MatSelectSearchComponent } from "ngx-mat-select-search";
import { deepCopy } from "../../components/util/util.service";
import { MatSelect } from "@angular/material/select";
import { DialogService } from "../../components/dialog/dialog.service";

export interface SelectConfiguration {
  /**
   * css class that should be applied for the selection.
   */
  cssClass?: string;
  /**
   * Title of component.
   */
  title?: string;
  /**
   * A flag that controls if the selection is mandatory or not. @default(false)
   */
  isMandatory?: boolean;
  /**
   * Allow multiple selection. @default(false)
   */
  multi?: boolean;
  /**
   * Allow group selection. @default(false)
   */
  grouped?: boolean;
  /**
   * The placeholder for the value.
   */
  placeholder?: string;
  /**
   * Whether the label should try to float or not. @default(false)
   */
  shouldLabelFloat?: boolean;
  /**
   * Add or Hide label. @default(false)
   */
  addLabel?: boolean;
  /**
   * The label name.
   */
  labelName?: string;
  /**
   * Enable or Disable custom mode. @default(false)
   */
  customValueMode?: boolean;
  /**
   * Enable or Disable clear options selected on reset. @default(false)
   */
  clearOptionsOnReset?: boolean;
  /**
   * Enable or Disable required selection. @default(false)
   */
  required?: boolean;
  /**
   * Whether the label for fields should by default float.
   */
  floatLabel?: string;
  /**
   * Values to be selected.
   */
  values?: any[];
  /**
   * Enable or disable group selection. @default(false)
   */
  enableGroupSelection?: boolean;
  /**
   * Storage key to keep the selected option.
   */
  "local-storage-key": string;
  /**
   * Storage key type to keep the selected option.
   */
  "local-storage-key-type"?: string;
  /**
   * Allow to fetch data from a stream, if true then data are fetched from input channel. @default(false)
   */
  "data-from-stream"?: boolean;
  /**
   * Fetch data of the select from a url.
   */
  "remote-data-url"?: string;
  /**
   * The datatype of the values that will be selected.
   */
  "remote-data-dataType"?: any;
  /**
   * The represented object value of the selection on emit.
   */
  "remote-data-value"?: string;
  /**
   * The value that is shown to the user on selection.
   */
  "remote-data-prompt"?: string;
  /**
   * Creating a small circle, typically containing a number or other short set of characters.
   */
  "remote-data-badge"?: string;
  /**
   * Extract value of UOM.
   */
  "remote-data-measurementUnit"?: string;
  /**
   * A flag to add 'ALL' as an option.
   */
  "add-all-option"?: boolean;
  /**
   * A flag to add empty option.
   */
  "remote-data-add-empty-option"?: boolean;

  /**
   * Title of the info-dialog. Should be a translation-key
   */
  infoTitle?: string;

  /**
   * Text of the info-dialog. Should be a translation-key
   */
  infoText?: string;

  /**
   * Sets width of select
   */
  selectWidth?: string;

  /**
   * Allow select search @default(true)
   */
  enableSelectSearch?: boolean;

  /**
   * Auto focus field.
   */
  autofocus?: boolean;
}
const uriTemplates = uriTemplates_;

export const GROUP_VALUE = "groupValue";
export const OPTION_VALUE = "optionValue";

@WidgetComponent("nm-select")
@Component({
  selector: "nm-select",
  templateUrl: "./select.component.html",
  styleUrls: ["./select.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SelectWidgetComponent implements OnDestroy, AfterViewInit {
  @WidgetId()
  public _id;

  @WidgetConfiguration()
  public configuration: WidgetConfig<SelectConfiguration>;

  /**
   * Outputs the selected value, whenever it changes. This will emit a single object, or an array (if in multi mode). The content is the property value of the options
   */
  @WidgetOutput()
  public selectedValue: Subject<any> = new ReplaySubject<any>(1);

  /**
   * Outputs the selected objects, whenever it changes. This will emit a single object, or an array (if in multi mode). The content is the whole option
   */
  @WidgetOutput()
  public selectedObject: Subject<any> = new BehaviorSubject<any>(null);

  /**
   * Takes a value as input that, if not null, will trigger a confirmation dialog on change before the changes are emitted
   */

  @WidgetInput()
  public payload: Subject<any> = new Subject<any>();

  /**
   * Takes the current locale as input. This is needed to reload the options if the language changes
   */
  @WidgetInput()
  public selectedUiLocale: Subject<any> = new ReplaySubject<any>(1);

  /**
   * Trigger the current selection to reset when triggered
   */
  @WidgetInput("reset")
  private resetChannel: Subject<any> = new Subject<any>();

  /**
   * Set the current selection to the inputted value when triggered
   */
  @WidgetInput("defaultSelection")
  private defaultSelection: Subject<any> = new ReplaySubject<any>(1);

  /**
   * The uri to fetch the options from
   */
  @WidgetInput("uri")
  private uri: Subject<any> = new Subject<any>();

  /**
   * Disable the selection
   */
  @WidgetInput("disabled")
  public disabled: Subject<any> = new BehaviorSubject<boolean>(false);

  /**
   * Alternative  to uri input for options
   */
  @WidgetInput("optionsInput")
  private optionsInput: Subject<any> = new Subject<any>();

  /**
   * Hide the selection
   */
  @WidgetInput("selectHide")
  private selectHide: Subject<boolean> = new Subject<boolean>();

  /**
   * Reset selection to default value
   */
  @WidgetInput("resetToDefault")
  private resetToDefault: Subject<any> = new Subject<any>();

  /**
   * Outputs selected value type only if enableGroupSelection configuration is set to true
   */
  @WidgetOutput("selectedValueType")
  private selectedValueType: Subject<any> = new ReplaySubject<any>(1);

  /**
   * Outputs selection when panel is closed, used mainly for multi-select
   */
  @WidgetOutput()
  public selectedArray: Subject<any> = new Subject<any>();

  /**
   * Updates required status of select
   */
  @WidgetInput("required")
  private requiredChannel: Subject<any> = new Subject<any>();

  @ViewChild("selectSearch") selectSearch: MatSelectSearchComponent;
  @ViewChild("matSelect") matSelect: MatSelect;

  public multi: boolean;
  public selection: any;
  public placeholder: string;
  public shouldLabelFloat: Boolean = false;
  public autofocus: Boolean = false;
  public floatLabel: string = "";
  public priorSelection: string;
  private selectionEntry: LocalStorageEntry;
  private selectionTypeEntry: LocalStorageEntry;
  public isMandatory: Boolean = false;
  public needsConfirmation: Boolean = false;
  public addEmptyOption: Boolean = false;
  public options: any[] = [];
  public initialOptions: any[] = [];
  public searchString: string;
  public filterCtrl: FormControl = new FormControl();
  public unsubscribe = NgUnsubscribe.create();
  public dataFromStream: Boolean = false;
  public grouped: boolean;
  public groupFilterCtrl: FormControl = new FormControl();
  public addAllOption: boolean = false;
  private addOptionFiltered: boolean = false;
  public hideSelect: boolean = false;
  public labelName: string;
  public addLabel: boolean = false;
  public allOption = { value: "ALL", prompt: "All" };
  private selectedDefault: any;
  public selectedRow: any;
  public cssClass: string;
  private newSelection: any;
  public customValueMode: boolean = false;
  public searchPlaceholder: string;
  public customValueObject = { value: "", prompt: "" };
  private clearOptionsOnReset: boolean;
  public required: boolean;
  public selectWidth: string;
  public enableSelectSearch: boolean;

  public enableGroupSelection: boolean;
  private subscription: Subscription;
  constructor(
    protected _widgetframeService: WidgetframeService,
    public dialog: DialogService,
    public translateService: TranslateService,
    protected localStorageService: LocalStorageService,
    protected _changeDetectorRef: ChangeDetectorRef,
    protected _progressbarService: ProgressbarService
  ) {}

  onSelectionChange(event) {
    this.newSelection = event.source.value;
    if (this.enableGroupSelection) {
      this.selectedOptionType(OPTION_VALUE);
    }
  }

  onChange() {
    if (!this.needsConfirmation) {
      if (
        this.isMandatory &&
        this.multi &&
        this.selection.includes(this.allOption.value) &&
        this.newSelection !== this.allOption.value
      ) {
        this.selection = [this.newSelection];
      }
      if (
        this.isMandatory &&
        this.multi &&
        this.addAllOption &&
        (this.newSelection === this.allOption.value ||
          this.selection.length === 0)
      ) {
        this.selection = [this.allOption.value];
      }
      if (
        this.isMandatory &&
        this.multi &&
        !this.addAllOption &&
        this.selection.length === 0
      ) {
        if (this.grouped) {
          this.selection = [this.options[0].groupValues[0]["value"]];
        } else {
          this.selection = [this.options[0]["value"]];
        }
      }
      if (this.customValueMode) {
        this.clearCustomValue();
      }
      this.storeAndSend();
    } else {
      let dialogRef = this.dialog.open(ConfirmationDialogComponent, {
        height: "400px",
        width: "400px",
      });
      dialogRef.componentInstance["title"] =
        this.translateService.instant("hl.confirmation");
      dialogRef.componentInstance["message"] = this.translateService.instant(
        "message.confirmation.unsavedChanges"
      );
      dialogRef.componentInstance["buttonAcceptTitle"] =
        this.translateService.instant("button.accept");
      dialogRef.componentInstance["buttonCancelTitle"] =
        this.translateService.instant("button.cancel");

      dialogRef.afterClosed().subscribe((confirmed) => {
        if (confirmed) {
          if (
            this.isMandatory &&
            this.multi &&
            this.selection.includes(this.allOption.value) &&
            this.newSelection !== this.allOption.value
          ) {
            this.selection = [this.newSelection];
          }
          if (
            this.isMandatory &&
            this.multi &&
            this.addAllOption &&
            (this.newSelection === this.allOption.value ||
              this.selection.length === 0)
          ) {
            this.selection = [this.allOption.value];
          }
          if (
            this.isMandatory &&
            this.multi &&
            !this.addAllOption &&
            this.selection.length === 0
          ) {
            if (this.grouped) {
              this.selection = [this.options[0].groupValues[0]["value"]];
            } else {
              this.selection = [this.options[0]["value"]];
            }
          }
          this.storeAndSend();
        } else {
          this.selection = this.priorSelection;
          this._changeDetectorRef.markForCheck();
        }
      });
    }
  }

  onOpenedChange(open) {
    open ? this.onOpen : this.onCloseSelect();
  }

  onOpen(open) {
    this.priorSelection = this.selection;
  }

  storeAndSend() {
    if (this.selectionEntry) {
      if (this.multi) {
        this.selectionEntry.value = JSON.stringify(this.selection);
      } else {
        this.selectionEntry.value = this.selection;
      }
    }
    let groupIdentifier;

    if (this.grouped && this.selection.includes("_" + GROUP_VALUE)) {
      groupIdentifier = this.selection.split("_" + GROUP_VALUE)[0];
      this.selectedValue.next(groupIdentifier);
    } else {
      this.selectedValue.next(this.selection);
    }
    if (this.options && this.grouped) {
      this.sendGroupedSelection(groupIdentifier);
    } else if (this.options) {
      this.selectedRow = this.options.filter(
        (option) => option.value == this.selection
      )[0];
      let filtered;
      if (this.multi) {
        filtered = this.initialOptions.filter(
          (option) =>
            this.selection.findIndex((val) => val == option.value) >= 0
        );
      } else {
        filtered = this.options.filter(
          (option) => option.value == this.selection
        );
      }
      if (this.customValueMode) {
        this.selectedObject.next(
          filtered.length > 0 || !this.selection || this.selection.length == 0
            ? filtered
            : [{ value: this.selection, prompt: this.selection }]
        );
      } else {
        this.selectedObject.next(filtered);
      }
    }

    this._changeDetectorRef.markForCheck();
  }

  selectGroupIdentifier(event) {
    this.selectedOptionType(GROUP_VALUE);
  }

  @WidgetConfigure()
  protected configureWidget(configuration: WidgetConfig<SelectConfiguration>) {
    this.cssClass = configuration.configuration["cssClass"]
      ? configuration.configuration["cssClass"]
      : "";
    let title = configuration.configuration["title"];
    this.isMandatory = configuration.configuration["isMandatory"]
      ? configuration.configuration["isMandatory"]
      : false;
    this.multi = configuration.configuration["multi"]
      ? configuration.configuration["multi"]
      : false;
    this.grouped = configuration.configuration["grouped"]
      ? configuration.configuration["grouped"]
      : false;
    this.placeholder = configuration.configuration["placeholder"];
    this.shouldLabelFloat = configuration.configuration["shouldLabelFloat"]
      ? configuration.configuration["shouldLabelFloat"]
      : false;
    this.autofocus = configuration.configuration["autofocus"]
      ? configuration.configuration["autofocus"]
      : false;
    this.floatLabel = configuration.configuration.floatLabel;
    if (configuration.configuration["local-storage-key"]) {
      this.selectionEntry = this.localStorageService.getLocalStorageEntry(
        configuration.configuration["local-storage-key"],
        Scope.GLOBAL,
        DeletionMode.NEVER
      );
    }
    if (configuration.configuration["local-storage-key-type"]) {
      this.selectionTypeEntry = this.localStorageService.getLocalStorageEntry(
        configuration.configuration["local-storage-key-type"],
        Scope.GLOBAL,
        DeletionMode.NEVER
      );
    }
    this.addEmptyOption = configuration.configuration[
      "remote-data-add-empty-option"
    ]
      ? configuration.configuration["remote-data-add-empty-option"]
      : false;
    this.dataFromStream =
      configuration.configuration["data-from-stream"] !== undefined
        ? configuration.configuration["data-from-stream"]
        : false;
    this.addLabel = configuration.configuration["addLabel"];
    this.labelName = configuration.configuration["labelName"];
    this.addAllOption =
      configuration.configuration["add-all-option"] !== undefined
        ? configuration.configuration["add-all-option"]
        : false;
    this.enableGroupSelection = configuration.configuration[
      "enableGroupSelection"
    ]
      ? configuration.configuration["enableGroupSelection"]
      : false;
    this.customValueMode = getOrDefault(
      configuration.configuration.customValueMode,
      false
    );
    this.searchPlaceholder = this.customValueMode
      ? "placeholder.search-and-save"
      : "placeholder.search";
    this.clearOptionsOnReset = getOrDefault(
      configuration.configuration.clearOptionsOnReset,
      false
    );
    this.required = getOrDefault(configuration.configuration.required, false);
    this.selectWidth = configuration.configuration.selectWidth;
    this.enableSelectSearch = getOrDefault(
      configuration.configuration.enableSelectSearch,
      true
    );

    if (configuration.configuration["values"]) {
      this.options = configuration.configuration["values"];
      this.initialOptions = configuration.configuration["values"];
      this.selectedDefault = configuration.configuration["default-value"];

      if (this.selectionEntry && this.selectionEntry.exists()) {
        const value = this.selectionEntry.value;
        if (this.multi === Array.isArray(value)) {
          this.selection = value;
        }
      } else if (
        this.isMandatory &&
        !configuration.configuration["remote-data-url"] &&
        !this.multi
      ) {
        this.selection = this.addAllOption
          ? this.allOption.value
          : this.options[0]["value"];
      } else if (
        !this.isMandatory &&
        !this.multi &&
        configuration.configuration["default-value"]
      ) {
        this.selection = configuration.configuration["default-value"];
      }
      this.storeAndSend();

      this.defaultSelection
        .asObservable()
        .pipe(takeUntil(this.unsubscribe))
        .subscribe((defaultSelection) => {
          this.selection = defaultSelection;
          this.storeAndSend();
          this._changeDetectorRef.markForCheck();
        });
    } else {
      if (configuration.configuration["remote-data-url"]) {
        this.selectedUiLocale
          .pipe(
            takeUntil(this.unsubscribe),
            map((locale) => {
              let uriParams = Object.assign({}, { locale: locale });
              return uriParams;
            }),
            map((uriParams) => {
              let template = uriTemplates(
                configuration.configuration["remote-data-url"]
              );
              return template.fill(uriParams);
            }),
            mergeMap((uri) => {
              return this._widgetframeService.getData(uri);
            })
          )
          .subscribe(
            (data) => {
              if (data && !(data.type && data.type === "ERROR")) {
                this.addOptions(data, configuration);
              }
            },
            (err) => {
              console.log(err);
            }
          );
      }
      if (configuration.configuration["remote-data-url-from-stream"]) {
        this.subscription = observableCombineLatest(
          this.uri.asObservable(),
          this.selectedUiLocale.asObservable(),
          function (uri, selectedUiLocale) {
            let template = uriTemplates(uri);
            let uriParams = Object.assign({}, { locale: selectedUiLocale });

            return template.fill(uriParams);
          }
        )
          .pipe(
            mergeMap((uri) => {
              return this._widgetframeService.getData(uri);
            })
          )
          .subscribe(
            (data) => {
              if (data && !(data.type && data.type === "ERROR")) {
                this.addOptions(data, configuration);
              }
            },
            (err) => {
              console.log(err);
            }
          );
      }
      if (configuration.configuration["data-from-stream"]) {
        this.optionsInput
          .pipe(takeUntil(this.unsubscribe))
          .subscribe((data) => {
            if (data) {
              this.addOptions(data, configuration);
            }
          });
      }
    }

    this.filterCtrl.valueChanges
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((val) => {
        this.filterOptions();
      });

    this.groupFilterCtrl.valueChanges
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.groupFilterOptions();
      });

    this.selectHide
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((selectHide) => {
        this.hideSelect = selectHide;
        this._changeDetectorRef.markForCheck();
      });

    this.payload.pipe(takeUntil(this.unsubscribe)).subscribe((data) => {
      if (data != null) {
        this.needsConfirmation = true;
      } else {
        this.needsConfirmation = false;
      }
    });

    this.resetChannel.pipe(takeUntil(this.unsubscribe)).subscribe((reset) => {
      if (this.multi) {
        this.selection = [];
      } else {
        this.selection = null;
      }

      if (this.selectionEntry) {
        this.selectionEntry.clear();
      }
      if (this.selectionTypeEntry) {
        this.selectionTypeEntry.clear();
      }
      if (this.clearOptionsOnReset) {
        this.initialOptions = [];
        this.options = [];
      }
      this.selectedValue.next(this.selection);
      this.selectedObject.next(null);
      this._changeDetectorRef.markForCheck();
    });

    this.resetToDefault
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((resetToDefault) => {
        if (this.grouped) {
          this.selection = this.addAllOption
            ? this.allOption.value
            : this.options[0]["groupValues"][0].value;
        } else {
          if (this.selectedDefault) {
            this.selection = this.selectedDefault;
          } else if (this.addAllOption) {
            this.selection = this.allOption.value;
          } else {
            this.selection = this.options[0]["value"];
          }
        }

        if (this.multi && this.selection && !Array.isArray(this.selection)) {
          this.selection = [this.selection];
        }
        this.storeAndSend();
        this._changeDetectorRef.markForCheck();
      });

    this.requiredChannel
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((required) => {
        this.required = required;
        this._changeDetectorRef.markForCheck();
      });
  }

  private addOptions(data: any, configuration: WidgetConfig) {
    this.options = [];
    if (this.grouped && data._embedded) {
      for (var entry of data._embedded[
        configuration.configuration["remote-data-dataType"]
      ]) {
        let option = {};
        option["groupName"] = entry.groupName;
        if (entry.groupIdentifier) {
          option["groupIdentifier"] = entry.groupIdentifier.concat(
            "_" + GROUP_VALUE
          );
        }
        option["groupValues"] = [];
        entry.groupValues.forEach((value) => {
          let groupValue = {};
          groupValue["value"] =
            value[configuration.configuration["remote-data-value"]].toString();
          groupValue["prompt"] =
            value[configuration.configuration["remote-data-prompt"]].toString();
          groupValue["_original"] = value;

          option["groupValues"].push(groupValue);
        });
        this.options.push(option);
      }
    } else if (data._embedded) {
      let badgeProperty = configuration.configuration["remote-data-badge"];
      let valueProperty = configuration.configuration["remote-data-value"];
      let promptProperty = configuration.configuration["remote-data-prompt"];
      let uomProperty =
        configuration.configuration["remote-data-measurementUnit"];

      for (var entry of data._embedded[
        configuration.configuration["remote-data-dataType"]
      ]) {
        let option: any = {};
        option["value"] = this.extract(entry, valueProperty);
        option["prompt"] = this.extract(entry, promptProperty);

        if (badgeProperty) {
          let chips: any = entry[badgeProperty];
          if (chips) {
            if (typeof chips === "string") {
              let chipElement: any = {};
              chipElement.value = chips;
              chipElement.color = "primary";
              option.chipList = [chipElement];
            } else if (chips instanceof Array) {
              let chipList = [];
              chips.forEach((chip) => {
                let chipElement: any = {};
                chipElement.value = chip.value;
                if (chip.color) {
                  chipElement.color = chip.color;
                } else {
                  chipElement.color = "primary";
                }
                chipList.push(chipElement);
              });
              option.chipList = chipList;
            }
          }
        }
        if (uomProperty) {
          option["measurementUnit"] = this.extract(entry, uomProperty);
        }
        if (option["_actions"] !== null) {
          option["_actions"] = entry["_actions"];
        }

        option["_original"] = entry;
        this.options.push(option);
      }
    } else {
      this.options = data.values;
    }

    this.selectedValue.next(null);
    if (this.selectionEntry && this.selectionEntry.exists()) {
      if (this.multi) {
        this.selection = JSON.parse(this.selectionEntry.value);
      } else {
        this.selection = this.selectionEntry.value;

        if (
          this.isMandatory &&
          (!this.selection ||
            this.selection === "null" ||
            !this.options?.some((option) => option.value == this.selection))
        ) {
          this.selectDefault();
        }
      }
      this.storeAndSend();
    } else {
      this.selectDefault();
    }
    this.initialOptions = [].concat(this.options);

    this.defaultSelection
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((defaultSelection) => {
        if (this.customValueMode && defaultSelection) {
          this.setDefaultCustomValue(defaultSelection);
        }
        this.selection = defaultSelection;
        this.selectedDefault = this.selection;
        this.storeAndSend();
      });
  }

  private selectDefault() {
    if (this.isMandatory && !this.multi && !this.grouped) {
      this.selection = this.addAllOption
        ? this.allOption.value
        : getOrDefault(this.options[0]?.["value"], []);
      this.storeAndSend();
    } else if (this.isMandatory && !this.multi && this.grouped) {
      this.selection = this.addAllOption
        ? this.allOption.value
        : getOrDefault(this.options[0]?.["groupValues"][0].value, []);
      this.storeAndSend();
    } else if (this.isMandatory && this.multi) {
      this.selection = this.addAllOption
        ? [this.allOption.value]
        : getOrDefault(this.options[0]?.["groupValues"][0].value, []);
      this.storeAndSend();
    }
  }

  private extract(value: any, property: string): string {
    if (property && value.hasOwnProperty(property)) {
      let result = value[property];

      return result ? result.toString() : null;
    }

    return null;
  }

  filterOptions(event?) {
    if (!this.options) {
      return;
    }
    // get the search keyword
    let search = event ? event : this.filterCtrl.value;
    if (search) {
      if (
        this.addAllOption &&
        this.translateService
          .instant(this.allOption["prompt"])
          .toLowerCase()
          .indexOf(search.toLowerCase().trim()) === -1
      ) {
        this.addAllOption = false;
        this.addOptionFiltered = true;
      }
      this.options = this.initialOptions.filter(
        (item) =>
          this.translateService
            .instant(item["prompt"])
            .toLowerCase()
            .indexOf(search.toLowerCase().trim()) > -1
      );
    } else {
      if (this.addOptionFiltered) {
        this.addAllOption = true;
        this.addOptionFiltered = false;
      }
      this.options = this.initialOptions.slice();
    }
    // this.options = search ? this.initialOptions.filter(item => {
    //   return this.translateService.instant(item["prompt"]).toLowerCase().indexOf(search) > -1;
    // }) : this.initialOptions.slice();
  }

  groupFilterOptions(event?) {
    if (!this.options) {
      return;
    }

    let search = event ? event : this.groupFilterCtrl.value;
    if (search) {
      this.options = [];
      if (
        this.addAllOption &&
        this.translateService
          .instant(this.allOption["prompt"])
          .toLowerCase()
          .indexOf(search.toLowerCase().trim()) === -1
      ) {
        this.addAllOption = false;
        this.addOptionFiltered = true;
      }
      this.initialOptions.forEach((item, index) => {
        let filteredOptions = [];
        filteredOptions = item.groupValues.filter(
          (value) =>
            this.translateService
              .instant(value["prompt"])
              .toLowerCase()
              .indexOf(search.toLowerCase().trim()) > -1
        );
        if (filteredOptions.length != 0) {
          let groupAttribute = JSON.parse(
            JSON.stringify(this.initialOptions[index])
          );
          groupAttribute.groupValues = filteredOptions;
          this.options.push(groupAttribute);
        }
      });
    } else {
      if (this.addOptionFiltered) {
        this.addAllOption = true;
        this.addOptionFiltered = false;
      }
      this.options = this.initialOptions.slice();
    }
  }

  sendGroupedSelection(groupIdentifier) {
    if (
      this.multi &&
      this.addAllOption &&
      this.selection.includes(this.allOption.value)
    ) {
      this.selectedObject.next([this.allOption]);
    } else if (this.multi) {
      let selectedOptions = [];
      this.options.forEach((item) => {
        let filteredOptions = item.groupValues.filter((option) =>
          this.selection.includes(option.value)
        );
        if (filteredOptions.length > 0) {
          selectedOptions = selectedOptions.concat(filteredOptions);
        }
      });
      this.selectedObject.next(selectedOptions);
    } else if (this.addAllOption && this.selection === this.allOption.value) {
      this.selectedObject.next(this.allOption);
    } else {
      for (let item of this.options) {
        if (groupIdentifier && item.groupIdentifier === groupIdentifier) {
          this.selectedObject.next({
            value: item.groupIdentifier,
            prompt: item.groupName,
          });
          break;
        }
        let filteredOption = item.groupValues.find(
          (option) => option.value === this.selection
        );
        if (filteredOption) {
          this.selectedObject.next(filteredOption);
          break;
        }
      }
    }
  }

  onCloseSelect() {
    if (this.customValueMode && this.multi) {
      this.clearMultiCustomValues(this.selection);
    }
    this.searchString = "";
    this.options = this.initialOptions.slice();
    this.selectedArray.next(this.selection);
  }

  ngAfterViewInit() {
    if (this.selectSearch && this.customValueMode) {
      this.selectSearch.searchSelectInput.nativeElement.onkeydown = (event) => {
        let valueEntered;
        if (this.grouped) {
          valueEntered = this.groupFilterCtrl.value;
        } else {
          valueEntered = this.filterCtrl.value;
        }
        if (
          event.keyCode == 13 &&
          valueEntered &&
          this.options.filter(
            (option) => option.prompt.toLowerCase() === valueEntered.trim()
          ).length == 0
        ) {
          event.stopPropagation();
          this.clearCustomValue();
          this.customValueObject.value = this.customValueObject.prompt =
            valueEntered;
          this.initialOptions.push(deepCopy(this.customValueObject));
          if (this.multi) {
            if (this.selection) {
              this.selection.push(valueEntered);
            } else {
              this.selection = [valueEntered];
            }
          } else {
            this.selection = valueEntered;
          }
          this.storeAndSend();
          this.matSelect.close();
        }
      };
    }
  }

  clearCustomValue() {
    if (!this.multi && this.customValueObject.value) {
      let customValueIndex = this.initialOptions.indexOf(
        this.customValueObject
      );
      this.initialOptions.splice(customValueIndex, 1);
      this.customValueObject.value = this.customValueObject.prompt = "";
    }
  }

  clearMultiCustomValues(selection: any) {
    let customAddedObjects = this.initialOptions.filter(
      (option) => !option._original
    );
    customAddedObjects.forEach((addedObject) => {
      if (!selection.includes(addedObject.value)) {
        let removedObjectIndex = this.initialOptions.findIndex(
          (option) => option.value === addedObject.value
        );
        this.initialOptions.splice(removedObjectIndex, 1);
      }
    });
    this.options = this.initialOptions;
  }

  setDefaultCustomValue(defaultSelection: any) {
    if (this.multi && !this.grouped) {
      defaultSelection.forEach((selection) => {
        if (
          this.initialOptions.filter((option) => option.value === selection)
            .length == 0
        ) {
          this.initialOptions.push({ value: selection, prompt: selection });
        }
      });
      this.options = this.initialOptions.slice();
      this.clearMultiCustomValues(defaultSelection);
    } else if (
      !this.multi &&
      !this.grouped &&
      !this.options.filter((option) => option.value === defaultSelection).length
    ) {
      this.customValueObject.value = this.customValueObject.prompt =
        defaultSelection;
      this.initialOptions.push(deepCopy(this.customValueObject));
      this.options = this.initialOptions.slice();
    }
  }

  selectedOptionType(optionType: string) {
    if (this.selectionTypeEntry) {
      this.selectionTypeEntry.value = optionType;
    }
    this.selectedValueType.next(optionType);
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
    this.unsubscribe.next();
    this.unsubscribe.destroy();
    this._progressbarService.requestFinished();
  }
}

results matching ""

    No results matching ""