src/app/shared/widgets/select-combo/select-combo.component.ts
Properties |
allowEmpty |
allowEmpty:
|
Type : boolean
|
Allow a empty value as option (@default:true) |
clearable |
clearable:
|
Type : boolean
|
|
customClass |
customClass:
|
Type : string
|
Sets the custom css class |
disabled |
disabled:
|
Type : boolean
|
|
displayKey |
displayKey:
|
Type : string
|
Value(relates to select options) displayed description key (@default:description) |
groupKey |
groupKey:
|
Type : string
|
If the data contains groups, this field either contains the parent reference or the child options |
identifier |
identifier:
|
Type : string
|
Identifier and name of this field |
multiple |
multiple:
|
Type : boolean
|
Allow multiple selection (@default: false) |
openOnFocus |
openOnFocus:
|
Type : boolean
|
Open options on focus (example over tabulator) (@default:false) |
optionsDataKey |
optionsDataKey:
|
Type : string
|
The key of embedded options-data in response of optionsDataUrl |
optionsDataUrl |
optionsDataUrl:
|
Type : string
|
Fetch options of the select element from a url. |
placeholder |
placeholder:
|
Type : string
|
Placeholder string to display |
preselectedValues |
preselectedValues:
|
Type : string[]
|
Id string-array of preselected values(relates to select options) (identifiers) |
showAllPlaceholder |
showAllPlaceholder:
|
Type : boolean
|
Show "All" in combo trigger when all values are selected (@default: false) |
tabIndex |
tabIndex:
|
Type : number
|
Tabulator click event order(@default:0) |
valueKey |
valueKey:
|
Type : string
|
Value(relates to select options) identifier key (@default:identifier) |
import {
WidgetComponent,
WidgetConfiguration,
WidgetConfigure,
WidgetInput,
WidgetOutput,
} from "../widget.metadata";
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
TemplateRef,
ViewChild,
} from "@angular/core";
import { getOrDefault, WidgetConfig } from "../widget.configuration";
import { BehaviorSubject, combineLatest, ReplaySubject, Subject } from "rxjs";
import { WidgetframeService } from "../widgetframe/widgetframe.service";
import {
debounceTime,
filter,
flatMap,
startWith,
takeUntil,
} from "rxjs/operators";
import { NgUnsubscribe } from "../../ng-unsubscribe";
import { CurrentLocaleService } from "../../components/i18n";
import { notNullOrEmpty } from "../../components/util";
import {
LocalStorageEntry,
LocalStorageService,
} from "../../components/local-storage/local-storage.service";
import {
DeletionMode,
Scope,
} from "../../components/local-storage/local-storage-constants";
import { GroupByStrategy } from "../../components/combo/nm-combo.api";
import { NmComboComponent } from "../../components/combo/nm-combo.component";
interface SelectComboConfiguration {
/**
* Tabulator click event order(@default:0)
*/
tabIndex: number;
/**
* Placeholder string to display
*/
placeholder: string;
/**
* `true` to disable the component (@default:false)
*/
disabled: boolean;
/**
* `true` to show the clear button (@default:true)
*/
clearable: boolean;
/**
* Value(relates to select options) identifier key (@default:identifier)
*/
valueKey: string;
/**
* Value(relates to select options) displayed description key (@default:description)
*/
displayKey: string;
/**
* Open options on focus (example over tabulator) (@default:false)
*/
openOnFocus: boolean;
/**
* Id string-array of preselected values(relates to select options) (identifiers)
*/
preselectedValues: string[];
/**
* Allow a empty value as option (@default:true)
*/
allowEmpty: boolean;
/**
* Identifier and name of this field
*/
identifier: string;
/**
* Fetch options of the select element from a url.
*/
optionsDataUrl: string;
/**
* The key of embedded options-data in response of optionsDataUrl
*/
optionsDataKey: string;
/**
* Sets the custom css class
*/
customClass: string;
/**
* If the data contains groups, this field either contains the parent reference or the child options
*/
groupKey: string;
/**
* "nested", groupKey should contain an array of options, "parent-reference": child options reference the valueKey field of their parent
*/
groupStrategy: GroupByStrategy;
/**
* Allow multiple selection (@default: false)
*/
multiple: boolean;
/**
* Show "All" in combo trigger when all values are selected (@default: false)
*/
showAllPlaceholder: boolean;
}
@WidgetComponent("nm-select-combo")
@Component({
selector: "nm-select-combo",
templateUrl: "./select-combo.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SelectComboComponent {
@WidgetConfiguration()
public configuration: WidgetConfig<SelectComboConfiguration>;
public _unsubscribe = NgUnsubscribe.create();
public _optionsDataUrl: string;
public _optionsDataKey: string;
public _preselectedValues: string[];
public _selectionLocalstorageEntry: LocalStorageEntry;
public _allLocalstorageEntry: LocalStorageEntry;
public identifier: string;
public options: any[];
public selectedValues: string[];
public valueKey: string;
public displayKey: string;
public tabIndex: number;
public openOnFocus: boolean;
public clearable: boolean;
public disabled: boolean;
public allowEmpty: boolean;
public filterPlaceholder: string;
public placeholder: string;
public customClass: string;
public groupKey: string;
public groupStrategy: GroupByStrategy;
public multiple: boolean;
public hide: boolean = false;
public showAllPlaceholder: boolean;
@WidgetInput("options-url")
public optionsDataUrl = new BehaviorSubject<string>("");
@WidgetInput("reload-options")
public reload = new Subject();
@WidgetInput("hide")
public hideChannel = new Subject<boolean>();
@WidgetInput()
public resetToDefault = new Subject<any>();
@WidgetOutput("option-selected")
public valueChanged = new ReplaySubject<any>(1);
@WidgetOutput("allSelected")
public allSelected = new ReplaySubject<boolean>(1);
@ViewChild("combo")
public combo: NmComboComponent;
constructor(
protected _widgetframeService: WidgetframeService,
protected _currentLocaleService: CurrentLocaleService,
protected cdr: ChangeDetectorRef,
protected localstorageService: LocalStorageService
) {}
@WidgetConfigure()
public configureWidget(
configuration: WidgetConfig<SelectComboConfiguration>
) {
this.valueKey = getOrDefault(
configuration.configuration.valueKey,
"identifier"
);
this.displayKey = getOrDefault(
configuration.configuration.displayKey,
"description"
);
this.tabIndex = getOrDefault(configuration.configuration.tabIndex, 0);
this.openOnFocus = getOrDefault(
configuration.configuration.openOnFocus,
false
);
this.clearable = getOrDefault(configuration.configuration.clearable, true);
this.disabled = getOrDefault(configuration.configuration.disabled, false);
this._preselectedValues = getOrDefault(
configuration.configuration.preselectedValues,
[]
);
// todo PIMCORE-6734 allow empty option
this.allowEmpty = getOrDefault(
configuration.configuration.allowEmpty,
true
);
this.identifier = getOrDefault(
configuration.configuration.identifier,
"select-combo-field"
);
this.customClass = getOrDefault(
configuration.configuration.customClass,
""
);
this.groupKey = configuration.configuration.groupKey;
this.groupStrategy = configuration.configuration.groupStrategy;
this.multiple = getOrDefault(configuration.configuration.multiple, false);
this._optionsDataUrl = configuration.configuration.optionsDataUrl;
this._optionsDataKey = configuration.configuration.optionsDataKey;
this.placeholder = configuration.configuration.placeholder;
this.showAllPlaceholder = configuration.configuration.showAllPlaceholder;
if (this._optionsDataUrl && !this._optionsDataKey) {
console.error(
'"_optionsDataKey" for widget "',
this.identifier,
'" missing!'
);
}
let localStorageKey = configuration.configuration["local-storage-key"];
if (localStorageKey) {
this._selectionLocalstorageEntry =
this.localstorageService.getLocalStorageEntry(
localStorageKey,
Scope.USER,
DeletionMode.RESET
);
if (this.showAllPlaceholder) {
this._allLocalstorageEntry =
this.localstorageService.getLocalStorageEntry(
"allSelected-" + localStorageKey,
Scope.USER,
DeletionMode.RESET
);
}
}
combineLatest([
this.optionsDataUrl.asObservable().pipe(
startWith(this._optionsDataUrl),
filter((url) => !!url)
),
this._currentLocaleService.getCurrentLocale(),
this.reload.asObservable().pipe(startWith(null)),
])
.pipe(
takeUntil(this._unsubscribe),
debounceTime(50),
flatMap((data) => {
return this._widgetframeService.getData(this._optionsDataUrl);
})
)
.subscribe((response) => {
if (response) {
this.options = response._embedded[this._optionsDataKey];
this.setPreselectValues();
}
});
this.hideChannel
.asObservable()
.pipe(takeUntil(this._unsubscribe))
.subscribe((hide) => {
this.hide = hide;
this.cdr.detectChanges();
});
this.resetToDefault
.asObservable()
.pipe(takeUntil(this._unsubscribe))
.subscribe((reset) => {
this.selectedValues = [];
if (this._selectionLocalstorageEntry) {
this._selectionLocalstorageEntry.clear();
}
this.setPreselectValues();
this.cdr.detectChanges();
});
}
public onChange(value: any) {
let _values = Array.isArray(value) ? value : [value];
this.selectedValues = _values;
this.valueChanged.next(_values);
if (this._selectionLocalstorageEntry) {
this._selectionLocalstorageEntry.value = JSON.stringify(_values);
}
}
private setPreselectValues() {
const flattened = this.combo._api.getFlatComboOptions(
this.options,
this.groupKey
);
// check for case @WidgetInput("options-url") changed and preselected value not exist in new options
if (notNullOrEmpty(this.selectedValues)) {
this.setValidSelectedValues(this.selectedValues, flattened);
} else {
if (notNullOrEmpty(this._preselectedValues)) {
this.setValidSelectedValues(this._preselectedValues, flattened);
} else if (
this._selectionLocalstorageEntry &&
this._selectionLocalstorageEntry.exists()
) {
this.selectedValues = JSON.parse(
this._selectionLocalstorageEntry.value
);
} else {
this.selectedValues = flattened
.filter((option) => option.default === true)
.map((option) => option[this.valueKey]);
}
}
this.isAllSelected(this.selectedValues.length === flattened.length);
this.valueChanged.next(this.selectedValues);
this.cdr.markForCheck();
}
private setValidSelectedValues(values: string[], options: any[]) {
let optionValueIDs = options.map((option) => option[this.valueKey]);
this.selectedValues = values.filter((valueId) =>
optionValueIDs.includes(valueId)
);
}
isAllSelected(allSelected) {
this.allSelected.next(allSelected);
if (this._allLocalstorageEntry) {
this._allLocalstorageEntry.value = allSelected;
}
}
}