src/app/shared/widgets/select/select.component.ts
Properties |
|
add-all-option |
add-all-option:
|
Type : boolean
|
Optional |
A flag to add 'ALL' as an option. |
addLabel |
addLabel:
|
Type : boolean
|
Optional |
Add or Hide label. @default(false) |
autofocus |
autofocus:
|
Type : boolean
|
Optional |
Auto focus field. |
clearOptionsOnReset |
clearOptionsOnReset:
|
Type : boolean
|
Optional |
Enable or Disable clear options selected on reset. @default(false) |
cssClass |
cssClass:
|
Type : string
|
Optional |
css class that should be applied for the selection. |
customValueMode |
customValueMode:
|
Type : boolean
|
Optional |
Enable or Disable custom mode. @default(false) |
data-from-stream |
data-from-stream:
|
Type : boolean
|
Optional |
Allow to fetch data from a stream, if true then data are fetched from input channel. @default(false) |
enableGroupSelection |
enableGroupSelection:
|
Type : boolean
|
Optional |
Enable or disable group selection. @default(false) |
enableSelectSearch |
enableSelectSearch:
|
Type : boolean
|
Optional |
Allow select search @default(true) |
floatLabel |
floatLabel:
|
Type : string
|
Optional |
Whether the label for fields should by default float. |
grouped |
grouped:
|
Type : boolean
|
Optional |
Allow group selection. @default(false) |
infoText |
infoText:
|
Type : string
|
Optional |
Text of the info-dialog. Should be a translation-key |
infoTitle |
infoTitle:
|
Type : string
|
Optional |
Title of the info-dialog. Should be a translation-key |
isMandatory |
isMandatory:
|
Type : boolean
|
Optional |
A flag that controls if the selection is mandatory or not. @default(false) |
labelName |
labelName:
|
Type : string
|
Optional |
The label name. |
local-storage-key |
local-storage-key:
|
Type : string
|
Storage key to keep the selected option. |
local-storage-key-type |
local-storage-key-type:
|
Type : string
|
Optional |
Storage key type to keep the selected option. |
multi |
multi:
|
Type : boolean
|
Optional |
Allow multiple selection. @default(false) |
placeholder |
placeholder:
|
Type : string
|
Optional |
The placeholder for the value. |
remote-data-add-empty-option |
remote-data-add-empty-option:
|
Type : boolean
|
Optional |
A flag to add empty option. |
remote-data-badge |
remote-data-badge:
|
Type : string
|
Optional |
Creating a small circle, typically containing a number or other short set of characters. |
remote-data-dataType |
remote-data-dataType:
|
Type : any
|
Optional |
The datatype of the values that will be selected. |
remote-data-measurementUnit |
remote-data-measurementUnit:
|
Type : string
|
Optional |
Extract value of UOM. |
remote-data-prompt |
remote-data-prompt:
|
Type : string
|
Optional |
The value that is shown to the user on selection. |
remote-data-url |
remote-data-url:
|
Type : string
|
Optional |
Fetch data of the select from a url. |
remote-data-value |
remote-data-value:
|
Type : string
|
Optional |
The represented object value of the selection on emit. |
required |
required:
|
Type : boolean
|
Optional |
Enable or Disable required selection. @default(false) |
selectWidth |
selectWidth:
|
Type : string
|
Optional |
Sets width of select |
shouldLabelFloat |
shouldLabelFloat:
|
Type : boolean
|
Optional |
Whether the label should try to float or not. @default(false) |
title |
title:
|
Type : string
|
Optional |
Title of component. |
values |
values:
|
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();
}
}