META-INF.frontend.uibuilder-combobox.src.uibuilder-combobox.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of uibuilder-combobox Show documentation
Show all versions of uibuilder-combobox Show documentation
A ComboBox component for the UIBuilder Framework
/*
*
* Copyright © 2018 Webvalto Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js'
import * as PolymerAsync from '@polymer/polymer/lib/utils/async.js';
import { ComboBoxElement } from '@vaadin/vaadin-combo-box/src/vaadin-combo-box.js';
import '@vaadin/flow-frontend/uibuilder/data/data-source-mixin.js';
import '@vaadin/flow-frontend/uibuilder-core/uibuilder-ready-listener-mixin.js';
export class UibuilderComboBox extends Uibuilder.DataSourceMixin(Uibuilder.ReadyListenerMixin(ComboBoxElement)) {
static get is() {
return 'uibuilder-combobox'
}
static get properties() {
return Object.assign({}, ComboBoxElement.properties, {
itemValuePath: {
type: String,
readOnly: true,
value: '___ITEM_KEY'
},
nullValuesDisabled: {
type: Boolean,
value: false,
notify: true
},
filteredItems: {
type: Array,
value: [],
observer: '_onFilteredItemsChange'
},
allowCustomValue: {
type: Boolean,
value: false,
notify: true
},
customValueFunction: {
type: String
}
});
}
constructor() {
super();
}
ready() {
super.ready();
this.filteredItems = []; // at this point, every combobox on the same screen has the same filteredItems reference, so it has to be reinitialized
this.clearButtonVisible = !this.nullValuesDisabled;
this.addEventListener('selected-item-changed', ({detail: {value = null}}) => {
const customEvent = new CustomEvent('item-changed');
customEvent.model = {item: value};
this.dispatchEvent(customEvent);
});
if (this.inputElement) {
this.inputElement.addEventListener("input", () => {
if (this.allowCustomValue) {
this._customValue = this._inputElementValue;
this.dispatchEvent(new CustomEvent("custom-value-changed", {
detail: {
customValue: this._customValue
}
}));
}
});
}
}
_dataProviderFilterChanged() {
this._debouncer = Debouncer.debounce(
this._debouncer,
PolymerAsync.timeOut.after(500),
() => super._dataProviderFilterChanged()
);
}
// override
// noinspection JSUnusedGlobalSymbols
_clear() {
if (!this.nullValuesDisabled) {
super._clear();
}
this._dispatchChanged();
}
// override
// noinspection JSUnusedGlobalSymbols
_valueChanged(value, oldVal) {
if (!this.nullValuesDisabled || value !== null) {
super._valueChanged(value, oldVal);
if (this.allowCustomValue) {
// if allowCustomValue is true, the super._valueChanged function will overwrite the input element's value
// to the raw value. The following line will try to extract the item label, if it is not a custom value,
// or return the custom value otherwise.
if (this.selectedItem) {
this._inputElementValue = this._getItemLabel(this.selectedItem);
} else if (!this.disabled) {
this._inputElementValue = this._customValue || "";
}
}
}
}
_uibuilderReady() {
this._ensureFirstPage(true);
this._processDataSourceTag();
}
_refresh() {
this.size = undefined;
this.clearCache();
}
_onItemSelected(item) {
if (item && item.___ITEM_IDX) {
this.valueIdx = item.___ITEM_IDX;
} else {
delete this.valueIdx;
}
this.value = item ? item.___ITEM_KEY : ' ';
this._handlePrematureItemSelection(item);
}
/**
* In case of a DB driven datasource, the filteredItems array may arrive later than the selected item is set.
* If it is the case, the selected item is stored in a variable, which can be used to set the selected item later
* when the filteredItems are set.
*
* Otherwise, if there are filteredItems present, there is no need to store the selection,
* so the variable will be removed.
*/
_handlePrematureItemSelection(item) {
if (item && (!this.filteredItems || this.filteredItems.length === 0)) {
this.prematureSelectedItem = item;
} else {
delete this.prematureSelectedItem;
}
}
/**
* To observe the change of the filteredItems and if there is a premature selection, apply the selection according
* to the items.
*/
_onFilteredItemsChange() {
if (this.filteredItems && this.filteredItems.length !== 0 && this.prematureSelectedItem) {
this._onItemSelected(this.prematureSelectedItem);
}
}
_getValueIndexInItems(value) {
let foundIdx = -1;
for (let idx in this.filteredItems) {
if (this.filteredItems && this.filteredItems[idx] && this.filteredItems[idx].___ITEM_KEY) {
let item = this.filteredItems[idx].___ITEM_KEY;
if (item === value) {
foundIdx = idx;
break;
}
}
}
return foundIdx;
}
_getNextPageNeededForValue() {
let pageToLoad = -1;
const currentLen = this._getRealItemLength();
if (currentLen === -1 || this.size === undefined || (currentLen < this.filteredItems.length)) {
pageToLoad = this._getPageForIndex(currentLen + 1);
}
if (this.valueIdx && this.valueIdx >= currentLen) {
pageToLoad = this._getPageForIndex(this.valueIdx);
}
return pageToLoad;
}
// override
// noinspection JSUnusedGlobalSymbols
_selectItemForValue(value) {
super._selectItemForValue(value);
if (this.filteredItems) {
let foundItem = this._getValueIndexInItems(value);
if (foundItem === -1) {
const pageToLoad = this._getNextPageNeededForValue();
if (pageToLoad !== -1 && value !== ' ') {
// selectedItem has to be undefined to trigger the next iteration of page load
this.set('selectedItem', undefined);
setTimeout(() => {
if (this.value === '') {
this.value = value;
}
this._loadPage(pageToLoad);
});
}
}
}
}
// override
// noinspection JSUnusedGlobalSymbols
_detectAndDispatchChange() {
if (this.value !== this._lastCommittedValue) {
if (this._isValueReallyChanged()) {
this._dispatchChanged();
}
this.dispatchEvent(new CustomEvent('change', {bubbles: true}));
this._lastCommittedValue = this.value;
}
}
_dispatchChanged() {
this.dispatchEvent(new CustomEvent('changed', {bubbles: true}));
}
_isValueReallyChanged() {
return !this._isValueInPendingState() || this.selectedItem;
}
_isValueInPendingState() {
return this._isValueUndefined() && !this._lastCommittedValue;
}
_isValueUndefined() {
return !this.value || this.value === '' || this.value === ' ';
}
_getRealItemLength() {
return this.filteredItems ? this.filteredItems.filter(item => item.hasOwnProperty('___ITEM_KEY')).length : -1;
}
}
customElements.define(UibuilderComboBox.is, UibuilderComboBox);
© 2015 - 2024 Weber Informatics LLC | Privacy Policy