@WidgetComponent

nm-select

File

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

Implements

OnDestroy AfterViewInit

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector nm-select
styleUrls select.component.scss
templateUrl ./select.component.html

Index

Widget inputs
Widget outputs
Properties
Methods

Constructor

constructor(_widgetframeService: WidgetframeService, dialog: DialogService, translateService: TranslateService, localStorageService: LocalStorageService, _changeDetectorRef: ChangeDetectorRef, _progressbarService: ProgressbarService)
Parameters :
Name Type Optional
_widgetframeService WidgetframeService no
dialog DialogService no
translateService TranslateService no
localStorageService LocalStorageService no
_changeDetectorRef ChangeDetectorRef no
_progressbarService ProgressbarService no

Methods

Private addOptions
addOptions(data: any, configuration: WidgetConfig)
Parameters :
Name Type Optional
data any no
configuration WidgetConfig no
Returns : void
clearCustomValue
clearCustomValue()
Returns : void
clearMultiCustomValues
clearMultiCustomValues(selection: any)
Parameters :
Name Type Optional
selection any no
Returns : void
Protected configureWidget
configureWidget(configuration: WidgetConfig)
Decorators : WidgetConfigure
Parameters :
Name Type Optional
configuration WidgetConfig<SelectConfiguration> no
Returns : void
Private extract
extract(value: any, property: string)
Parameters :
Name Type Optional
value any no
property string no
Returns : string
filterOptions
filterOptions(event?: )
Parameters :
Name Optional
event yes
Returns : void
groupFilterOptions
groupFilterOptions(event?: )
Parameters :
Name Optional
event yes
Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
onChange
onChange()
Returns : void
onCloseSelect
onCloseSelect()
Returns : void
onOpen
onOpen(open: )
Parameters :
Name Optional
open no
Returns : void
onOpenedChange
onOpenedChange(open: )
Parameters :
Name Optional
open no
Returns : void
onSelectionChange
onSelectionChange(event: )
Parameters :
Name Optional
event no
Returns : void
Private selectDefault
selectDefault()
Returns : void
selectedOptionType
selectedOptionType(optionType: string)
Parameters :
Name Type Optional
optionType string no
Returns : void
selectGroupIdentifier
selectGroupIdentifier(event: )
Parameters :
Name Optional
event no
Returns : void
sendGroupedSelection
sendGroupedSelection(groupIdentifier: )
Parameters :
Name Optional
groupIdentifier no
Returns : void
setDefaultCustomValue
setDefaultCustomValue(defaultSelection: any)
Parameters :
Name Type Optional
defaultSelection any no
Returns : void
storeAndSend
storeAndSend()
Returns : void

Properties

Public _id
_id:
Decorators : WidgetId
Public addAllOption
addAllOption: boolean
Type : boolean
Default value : false
Public addEmptyOption
addEmptyOption: Boolean
Type : Boolean
Default value : false
Public addLabel
addLabel: boolean
Type : boolean
Default value : false
Private addOptionFiltered
addOptionFiltered: boolean
Type : boolean
Default value : false
Public allOption
allOption: object
Type : object
Default value : { value: "ALL", prompt: "All" }
Public autofocus
autofocus: Boolean
Type : Boolean
Default value : false
Private clearOptionsOnReset
clearOptionsOnReset: boolean
Type : boolean
Public configuration
configuration: WidgetConfig<SelectConfiguration>
Type : WidgetConfig<SelectConfiguration>
Decorators : WidgetConfiguration
Public cssClass
cssClass: string
Type : string
Public customValueMode
customValueMode: boolean
Type : boolean
Default value : false
Public customValueObject
customValueObject: object
Type : object
Default value : { value: "", prompt: "" }
Public dataFromStream
dataFromStream: Boolean
Type : Boolean
Default value : false
Private defaultSelection
defaultSelection: Subject<any>
Type : Subject<any>
Default value : new ReplaySubject<any>(1)
Decorators : WidgetInput

Set the current selection to the inputted value when triggered

Public dialog
dialog: DialogService
Type : DialogService
Public disabled
disabled: Subject<any>
Type : Subject<any>
Default value : new BehaviorSubject<boolean>(false)
Decorators : WidgetInput

Disable the selection

Public enableGroupSelection
enableGroupSelection: boolean
Type : boolean
Public enableSelectSearch
enableSelectSearch: boolean
Type : boolean
Public filterCtrl
filterCtrl: FormControl
Type : FormControl
Default value : new FormControl()
Public floatLabel
floatLabel: string
Type : string
Default value : ""
Public grouped
grouped: boolean
Type : boolean
Public groupFilterCtrl
groupFilterCtrl: FormControl
Type : FormControl
Default value : new FormControl()
Public hideSelect
hideSelect: boolean
Type : boolean
Default value : false
Public initialOptions
initialOptions: any[]
Type : any[]
Default value : []
Public isMandatory
isMandatory: Boolean
Type : Boolean
Default value : false
Public labelName
labelName: string
Type : string
matSelect
matSelect: MatSelect
Type : MatSelect
Decorators : ViewChild
Public multi
multi: boolean
Type : boolean
Public needsConfirmation
needsConfirmation: Boolean
Type : Boolean
Default value : false
Private newSelection
newSelection: any
Type : any
Public options
options: any[]
Type : any[]
Default value : []
Private optionsInput
optionsInput: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

Alternative to uri input for options

Public payload
payload: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

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

Public placeholder
placeholder: string
Type : string
Public priorSelection
priorSelection: string
Type : string
Public required
required: boolean
Type : boolean
Private requiredChannel
requiredChannel: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

Updates required status of select

Private resetChannel
resetChannel: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

Trigger the current selection to reset when triggered

Private resetToDefault
resetToDefault: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

Reset selection to default value

Public searchPlaceholder
searchPlaceholder: string
Type : string
Public searchString
searchString: string
Type : string
Public selectedArray
selectedArray: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetOutput

Outputs selection when panel is closed, used mainly for multi-select

Private selectedDefault
selectedDefault: any
Type : any
Public selectedObject
selectedObject: Subject<any>
Type : Subject<any>
Default value : new BehaviorSubject<any>(null)
Decorators : WidgetOutput

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

Public selectedRow
selectedRow: any
Type : any
Public selectedUiLocale
selectedUiLocale: Subject<any>
Type : Subject<any>
Default value : new ReplaySubject<any>(1)
Decorators : WidgetInput

Takes the current locale as input. This is needed to reload the options if the language changes

Public selectedValue
selectedValue: Subject<any>
Type : Subject<any>
Default value : new ReplaySubject<any>(1)
Decorators : WidgetOutput

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

Private selectedValueType
selectedValueType: Subject<any>
Type : Subject<any>
Default value : new ReplaySubject<any>(1)
Decorators : WidgetOutput

Outputs selected value type only if enableGroupSelection configuration is set to true

Private selectHide
selectHide: Subject<boolean>
Type : Subject<boolean>
Default value : new Subject<boolean>()
Decorators : WidgetInput

Hide the selection

Public selection
selection: any
Type : any
Private selectionEntry
selectionEntry: LocalStorageEntry
Type : LocalStorageEntry
Private selectionTypeEntry
selectionTypeEntry: LocalStorageEntry
Type : LocalStorageEntry
selectSearch
selectSearch: MatSelectSearchComponent
Type : MatSelectSearchComponent
Decorators : ViewChild
Public selectWidth
selectWidth: string
Type : string
Public shouldLabelFloat
shouldLabelFloat: Boolean
Type : Boolean
Default value : false
Private subscription
subscription: Subscription
Type : Subscription
Public translateService
translateService: TranslateService
Type : TranslateService
Public unsubscribe
unsubscribe:
Default value : NgUnsubscribe.create()
Private uri
uri: Subject<any>
Type : Subject<any>
Default value : new Subject<any>()
Decorators : WidgetInput

The uri to fetch the options from

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();
  }
}
<div *ngIf="!hideSelect" class="nm-select mat-body">
  <div *ngIf="addLabel" class="nm-select__label">
    <nm-ellipsis [content]="labelName | translate"></nm-ellipsis>
  </div>

  <mat-form-field
    [style.width]="selectWidth"
    [floatLabel]="floatLabel"
    [ngClass]="{ '--withLabel': addLabel }"
    *ngIf="!grouped; else groupedSelect"
  >
    <mat-select
      style="width: 100%"
      [disabled]="disabled | async"
      [(ngModel)]="selection"
      #model="ngModel"
      panelClass="testClass"
      (openedChange)="onOpenedChange($event)"
      (onClose)="onCloseSelect()"
      [multiple]="multi"
      (selectionChange)="onChange()"
      [placeholder]="placeholder | translate"
      [name]="configuration.configuration['name']"
      [id]="configuration.configuration['name']"
      [panelClass]="cssClass"
      [required]="required"
      [nmAutofocus]="configuration.configuration.autofocus"
      #matSelect
    >
      <mat-select-trigger *ngIf="selectedRow">
        {{ selectedRow.prompt | translate }}
        <div class="nm-select-chips" *ngIf="selectedRow.chipList">
          <nm-chip
            *ngFor="let chip of selectedRow.chipList"
            class="nm-select-chips__chip"
            [modifier]="chip.color"
            [content]="chip.value"
            [toUpperCase]="true"
          >
          </nm-chip>
        </div>
      </mat-select-trigger>
      <mat-option *ngIf="enableSelectSearch">
        <ngx-mat-select-search
          [formControl]="filterCtrl"
          placeholderLabel="{{ searchPlaceholder | translate }}"
          noEntriesFoundLabel="{{ 'select.no.options' | translate }}"
          (keydown.escape)="selectSearch.matSelect.focus()"
          #selectSearch
        ></ngx-mat-select-search>
      </mat-option>

      <mat-option *ngIf="addEmptyOption" (click)="model.reset()"></mat-option>
      <mat-option
        *ngIf="addAllOption"
        [value]="allOption.value"
        (onSelectionChange)="onSelectionChange($event)"
      >
        {{ allOption.prompt | translate }}
      </mat-option>
      <mat-option
        *ngFor="let option of options"
        [value]="option.value"
        (onSelectionChange)="onSelectionChange($event)"
        [disabled]="option.disabled"
      >
        <span>
          {{ option.prompt | translate }}
          <div class="nm-select-chips" *ngIf="option.chipList">
            <nm-chip
              *ngFor="let chip of option.chipList"
              class="nm-select-chips__chip"
              [modifier]="chip.color"
              [content]="chip.value"
              [toUpperCase]="true"
            >
            </nm-chip>
          </div>
        </span>
      </mat-option>
    </mat-select>
  </mat-form-field>
  <ng-template #groupedSelect>
    <mat-form-field
      [style.width]="selectWidth"
      [floatLabel]="floatLabel"
      [ngClass]="{ '--withLabel': addLabel }"
    >
      <mat-select
        style="width: 100%"
        [(ngModel)]="selection"
        (selectionChange)="onChange()"
        #model="ngModel"
        [disabled]="disabled | async"
        (openedChange)="onOpenedChange($event)"
        shouldLabelFloat="shouldLabelFloat"
        [placeholder]="placeholder | translate"
        [name]="configuration.configuration['name']"
        [id]="configuration.configuration['name']"
        [panelClass]="cssClass"
        [multiple]="multi"
        [required]="required"
        #matSelect
      >
        <mat-option *ngIf="enableSelectSearch">
          <ngx-mat-select-search
            [formControl]="groupFilterCtrl"
            placeholderLabel="{{ searchPlaceholder | translate }}"
            noEntriesFoundLabel="{{ 'select.no.options' | translate }}"
            #selectSearch
          ></ngx-mat-select-search>
        </mat-option>
        <mat-option *ngIf="addEmptyOption" (click)="model.reset()"></mat-option>
        <ng-container *ngIf="!enableGroupSelection">
          <mat-option
            *ngIf="addAllOption"
            [value]="allOption.value"
            (onSelectionChange)="onSelectionChange($event)"
          >
            {{ allOption.prompt | translate }}
          </mat-option>
          <mat-optgroup *ngFor="let group of options" [label]="group.groupName">
            <mat-option
              *ngFor="let option of group.groupValues"
              [value]="option.value"
              (onSelectionChange)="onSelectionChange($event)"
              [disabled]="option.disabled"
            >
              {{ option.prompt | translate }}
            </mat-option>
          </mat-optgroup>
        </ng-container>
        <ng-container *ngIf="enableGroupSelection">
          <mat-option
            *ngIf="addAllOption"
            [value]="allOption.value"
            (onSelectionChange)="
              $event.source.selected ? onSelectionChange($event) : ''
            "
          >
            {{ allOption.prompt | translate }}
          </mat-option>
          <ng-container *ngFor="let group of options">
            <mat-option
              [value]="group.groupIdentifier"
              (onSelectionChange)="
                $event.source.selected ? selectGroupIdentifier($event) : ''
              "
              [disabled]="group.disabled"
            >
              {{ group.groupName | translate }}
            </mat-option>
            <mat-option
              *ngFor="let option of group.groupValues"
              [value]="option.value"
              style="padding-left: 32px"
              (onSelectionChange)="
                $event.source.selected ? onSelectionChange($event) : ''
              "
              [disabled]="option.disabled"
            >
              {{ option.prompt | translate }}
            </mat-option>
          </ng-container>
        </ng-container>
      </mat-select>
    </mat-form-field>
  </ng-template>

  <nm-help-icon
    class="nm-help-icon"
    *ngIf="configuration.configuration.infoText"
    [info-title]="configuration.configuration.infoTitle"
    [info-placement]="'bottom'"
    [info-text]="configuration.configuration.infoText"
  >
  </nm-help-icon>
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""