1869 lines
85 KiB
JavaScript
1869 lines
85 KiB
JavaScript
import * as i2 from '@angular/common';
|
|
import { DOCUMENT, CommonModule } from '@angular/common';
|
|
import * as i0 from '@angular/core';
|
|
import { forwardRef, EventEmitter, signal, computed, effect, numberAttribute, booleanAttribute, Component, ChangeDetectionStrategy, ViewEncapsulation, Inject, Input, Output, ViewChild, ContentChildren, NgModule } from '@angular/core';
|
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
import * as i1 from 'primeng/api';
|
|
import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api';
|
|
import * as i7 from 'primeng/autofocus';
|
|
import { AutoFocusModule } from 'primeng/autofocus';
|
|
import * as i4 from 'primeng/button';
|
|
import { ButtonModule } from 'primeng/button';
|
|
import { DomHandler } from 'primeng/dom';
|
|
import { InputTextModule } from 'primeng/inputtext';
|
|
import * as i3 from 'primeng/overlay';
|
|
import { OverlayModule } from 'primeng/overlay';
|
|
import * as i5 from 'primeng/ripple';
|
|
import { RippleModule } from 'primeng/ripple';
|
|
import * as i6 from 'primeng/scroller';
|
|
import { ScrollerModule } from 'primeng/scroller';
|
|
import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
|
|
import { TimesCircleIcon } from 'primeng/icons/timescircle';
|
|
import { SpinnerIcon } from 'primeng/icons/spinner';
|
|
import { TimesIcon } from 'primeng/icons/times';
|
|
import { ChevronDownIcon } from 'primeng/icons/chevrondown';
|
|
|
|
const AUTOCOMPLETE_VALUE_ACCESSOR = {
|
|
provide: NG_VALUE_ACCESSOR,
|
|
useExisting: forwardRef(() => AutoComplete),
|
|
multi: true
|
|
};
|
|
/**
|
|
* AutoComplete is an input component that provides real-time suggestions when being typed.
|
|
* @group Components
|
|
*/
|
|
class AutoComplete {
|
|
document;
|
|
el;
|
|
renderer;
|
|
cd;
|
|
config;
|
|
overlayService;
|
|
zone;
|
|
/**
|
|
* Minimum number of characters to initiate a search.
|
|
* @group Props
|
|
*/
|
|
minLength = 1;
|
|
/**
|
|
* Delay between keystrokes to wait before sending a query.
|
|
* @group Props
|
|
*/
|
|
delay = 300;
|
|
/**
|
|
* Inline style of the component.
|
|
* @group Props
|
|
*/
|
|
style;
|
|
/**
|
|
* Inline style of the overlay panel element.
|
|
* @group Props
|
|
*/
|
|
panelStyle;
|
|
/**
|
|
* Style class of the component.
|
|
* @group Props
|
|
*/
|
|
styleClass;
|
|
/**
|
|
* Style class of the overlay panel element.
|
|
* @group Props
|
|
*/
|
|
panelStyleClass;
|
|
/**
|
|
* Inline style of the input field.
|
|
* @group Props
|
|
*/
|
|
inputStyle;
|
|
/**
|
|
* Identifier of the focus input to match a label defined for the component.
|
|
* @group Props
|
|
*/
|
|
inputId;
|
|
/**
|
|
* Inline style of the input field.
|
|
* @group Props
|
|
*/
|
|
inputStyleClass;
|
|
/**
|
|
* Hint text for the input field.
|
|
* @group Props
|
|
*/
|
|
placeholder;
|
|
/**
|
|
* When present, it specifies that the input cannot be typed.
|
|
* @group Props
|
|
*/
|
|
readonly;
|
|
/**
|
|
* When present, it specifies that the component should be disabled.
|
|
* @group Props
|
|
*/
|
|
disabled;
|
|
/**
|
|
* Maximum height of the suggestions panel.
|
|
* @group Props
|
|
*/
|
|
scrollHeight = '200px';
|
|
/**
|
|
* Defines if data is loaded and interacted with in lazy manner.
|
|
* @group Props
|
|
*/
|
|
lazy = false;
|
|
/**
|
|
* Whether the data should be loaded on demand during scroll.
|
|
* @group Props
|
|
*/
|
|
virtualScroll;
|
|
/**
|
|
* Height of an item in the list for VirtualScrolling.
|
|
* @group Props
|
|
*/
|
|
virtualScrollItemSize;
|
|
/**
|
|
* Whether to use the scroller feature. The properties of scroller component can be used like an object in it.
|
|
* @group Props
|
|
*/
|
|
virtualScrollOptions;
|
|
/**
|
|
* Maximum number of character allows in the input field.
|
|
* @group Props
|
|
*/
|
|
maxlength;
|
|
/**
|
|
* Name of the input element.
|
|
* @group Props
|
|
*/
|
|
name;
|
|
/**
|
|
* When present, it specifies that an input field must be filled out before submitting the form.
|
|
* @group Props
|
|
*/
|
|
required;
|
|
/**
|
|
* Size of the input field.
|
|
* @group Props
|
|
*/
|
|
size;
|
|
/**
|
|
* Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name).
|
|
* @group Props
|
|
*/
|
|
appendTo;
|
|
/**
|
|
* When enabled, highlights the first item in the list by default.
|
|
* @group Props
|
|
*/
|
|
autoHighlight;
|
|
/**
|
|
* When present, autocomplete clears the manual input if it does not match of the suggestions to force only accepting values from the suggestions.
|
|
* @group Props
|
|
*/
|
|
forceSelection;
|
|
/**
|
|
* Type of the input, defaults to "text".
|
|
* @group Props
|
|
*/
|
|
type = 'text';
|
|
/**
|
|
* Whether to automatically manage layering.
|
|
* @group Props
|
|
*/
|
|
autoZIndex = true;
|
|
/**
|
|
* Base zIndex value to use in layering.
|
|
* @group Props
|
|
*/
|
|
baseZIndex = 0;
|
|
/**
|
|
* Defines a string that labels the input for accessibility.
|
|
* @group Props
|
|
*/
|
|
ariaLabel;
|
|
/**
|
|
* Defines a string that labels the dropdown button for accessibility.
|
|
* @group Props
|
|
*/
|
|
dropdownAriaLabel;
|
|
/**
|
|
* Specifies one or more IDs in the DOM that labels the input field.
|
|
* @group Props
|
|
*/
|
|
ariaLabelledBy;
|
|
/**
|
|
* Icon class of the dropdown icon.
|
|
* @group Props
|
|
*/
|
|
dropdownIcon;
|
|
/**
|
|
* Ensures uniqueness of selected items on multiple mode.
|
|
* @group Props
|
|
*/
|
|
unique = true;
|
|
/**
|
|
* Whether to display options as grouped when nested options are provided.
|
|
* @group Props
|
|
*/
|
|
group;
|
|
/**
|
|
* Whether to run a query when input receives focus.
|
|
* @group Props
|
|
*/
|
|
completeOnFocus = false;
|
|
/**
|
|
* When enabled, a clear icon is displayed to clear the value.
|
|
* @group Props
|
|
*/
|
|
showClear = false;
|
|
/**
|
|
* Field of a suggested object to resolve and display.
|
|
* @group Props
|
|
* @deprecated use optionLabel property instead
|
|
*/
|
|
field;
|
|
/**
|
|
* Displays a button next to the input field when enabled.
|
|
* @group Props
|
|
*/
|
|
dropdown;
|
|
/**
|
|
* Whether to show the empty message or not.
|
|
* @group Props
|
|
*/
|
|
showEmptyMessage = true;
|
|
/**
|
|
* Specifies the behavior dropdown button. Default "blank" mode sends an empty string and "current" mode sends the input value.
|
|
* @group Props
|
|
*/
|
|
dropdownMode = 'blank';
|
|
/**
|
|
* Specifies if multiple values can be selected.
|
|
* @group Props
|
|
*/
|
|
multiple;
|
|
/**
|
|
* Index of the element in tabbing order.
|
|
* @group Props
|
|
*/
|
|
tabindex;
|
|
/**
|
|
* A property to uniquely identify a value in options.
|
|
* @group Props
|
|
*/
|
|
dataKey;
|
|
/**
|
|
* Text to display when there is no data. Defaults to global value in i18n translation configuration.
|
|
* @group Props
|
|
*/
|
|
emptyMessage;
|
|
/**
|
|
* Transition options of the show animation.
|
|
* @group Props
|
|
*/
|
|
showTransitionOptions = '.12s cubic-bezier(0, 0, 0.2, 1)';
|
|
/**
|
|
* Transition options of the hide animation.
|
|
* @group Props
|
|
*/
|
|
hideTransitionOptions = '.1s linear';
|
|
/**
|
|
* When present, it specifies that the component should automatically get focus on load.
|
|
* @group Props
|
|
*/
|
|
autofocus;
|
|
/**
|
|
* Used to define a string that autocomplete attribute the current element.
|
|
* @group Props
|
|
*/
|
|
autocomplete = 'off';
|
|
/**
|
|
* Name of the options field of an option group.
|
|
* @group Props
|
|
*/
|
|
optionGroupChildren = 'items';
|
|
/**
|
|
* Name of the label field of an option group.
|
|
* @group Props
|
|
*/
|
|
optionGroupLabel = 'label';
|
|
/**
|
|
* Options for the overlay element.
|
|
* @group Props
|
|
*/
|
|
overlayOptions;
|
|
/**
|
|
* An array of suggestions to display.
|
|
* @group Props
|
|
*/
|
|
get suggestions() {
|
|
return this._suggestions();
|
|
}
|
|
set suggestions(value) {
|
|
this._suggestions.set(value);
|
|
this.handleSuggestionsChange();
|
|
}
|
|
/**
|
|
* Element dimensions of option for virtual scrolling.
|
|
* @group Props
|
|
* @deprecated use virtualScrollItemSize property instead.
|
|
*/
|
|
get itemSize() {
|
|
return this._itemSize;
|
|
}
|
|
set itemSize(val) {
|
|
this._itemSize = val;
|
|
console.warn('The itemSize property is deprecated, use virtualScrollItemSize property instead.');
|
|
}
|
|
/**
|
|
* Property name or getter function to use as the label of an option.
|
|
* @group Props
|
|
*/
|
|
optionLabel;
|
|
/**
|
|
* Property name or getter function to use as the value of an option.
|
|
* @group Props
|
|
*/
|
|
optionValue;
|
|
/**
|
|
* Unique identifier of the component.
|
|
* @group Props
|
|
*/
|
|
id;
|
|
/**
|
|
* Text to display when the search is active. Defaults to global value in i18n translation configuration.
|
|
* @group Props
|
|
* @defaultValue '{0} results are available'
|
|
*/
|
|
searchMessage;
|
|
/**
|
|
* Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.
|
|
* @group Props
|
|
* @defaultValue 'No selected item'
|
|
*/
|
|
emptySelectionMessage;
|
|
/**
|
|
* Text to be displayed in hidden accessible field when options are selected. Defaults to global value in i18n translation configuration.
|
|
* @group Props
|
|
* @defaultValue '{0} items selected'
|
|
*/
|
|
selectionMessage;
|
|
/**
|
|
* Whether to focus on the first visible or selected element when the overlay panel is shown.
|
|
* @group Props
|
|
*/
|
|
autoOptionFocus = false;
|
|
/**
|
|
* When enabled, the focused option is selected.
|
|
* @group Props
|
|
*/
|
|
selectOnFocus;
|
|
/**
|
|
* Locale to use in searching. The default locale is the host environment's current locale.
|
|
* @group Props
|
|
*/
|
|
searchLocale;
|
|
/**
|
|
* Property name or getter function to use as the disabled flag of an option, defaults to false when not defined.
|
|
* @group Props
|
|
*/
|
|
optionDisabled;
|
|
/**
|
|
* When enabled, the hovered option will be focused.
|
|
* @group Props
|
|
*/
|
|
focusOnHover;
|
|
/**
|
|
* Specifies the input variant of the component.
|
|
* @group Props
|
|
*/
|
|
variant = 'outlined';
|
|
/**
|
|
* Callback to invoke to search for suggestions.
|
|
* @param {AutoCompleteCompleteEvent} event - Custom complete event.
|
|
* @group Emits
|
|
*/
|
|
completeMethod = new EventEmitter();
|
|
/**
|
|
* Callback to invoke when a suggestion is selected.
|
|
* @param {AutoCompleteSelectEvent} event - custom select event.
|
|
* @group Emits
|
|
*/
|
|
onSelect = new EventEmitter();
|
|
/**
|
|
* Callback to invoke when a selected value is removed.
|
|
* @param {AutoCompleteUnselectEvent} event - custom unselect event.
|
|
* @group Emits
|
|
*/
|
|
onUnselect = new EventEmitter();
|
|
/**
|
|
* Callback to invoke when the component receives focus.
|
|
* @param {Event} event - Browser event.
|
|
* @group Emits
|
|
*/
|
|
onFocus = new EventEmitter();
|
|
/**
|
|
* Callback to invoke when the component loses focus.
|
|
* @param {Event} event - Browser event.
|
|
* @group Emits
|
|
*/
|
|
onBlur = new EventEmitter();
|
|
/**
|
|
* Callback to invoke to when dropdown button is clicked.
|
|
* @param {AutoCompleteDropdownClickEvent} event - custom dropdown click event.
|
|
* @group Emits
|
|
*/
|
|
onDropdownClick = new EventEmitter();
|
|
/**
|
|
* Callback to invoke when clear button is clicked.
|
|
* @param {Event} event - Browser event.
|
|
* @group Emits
|
|
*/
|
|
onClear = new EventEmitter();
|
|
/**
|
|
* Callback to invoke on input key up.
|
|
* @param {KeyboardEvent} event - Keyboard event.
|
|
* @group Emits
|
|
*/
|
|
onKeyUp = new EventEmitter();
|
|
/**
|
|
* Callback to invoke on overlay is shown.
|
|
* @param {Event} event - Browser event.
|
|
* @group Emits
|
|
*/
|
|
onShow = new EventEmitter();
|
|
/**
|
|
* Callback to invoke on overlay is hidden.
|
|
* @param {Event} event - Browser event.
|
|
* @group Emits
|
|
*/
|
|
onHide = new EventEmitter();
|
|
/**
|
|
* Callback to invoke on lazy load data.
|
|
* @param {AutoCompleteLazyLoadEvent} event - Lazy load event.
|
|
* @group Emits
|
|
*/
|
|
onLazyLoad = new EventEmitter();
|
|
containerEL;
|
|
inputEL;
|
|
multiInputEl;
|
|
multiContainerEL;
|
|
dropdownButton;
|
|
itemsViewChild;
|
|
scroller;
|
|
overlayViewChild;
|
|
templates;
|
|
_itemSize;
|
|
itemsWrapper;
|
|
itemTemplate;
|
|
emptyTemplate;
|
|
headerTemplate;
|
|
footerTemplate;
|
|
selectedItemTemplate;
|
|
groupTemplate;
|
|
loaderTemplate;
|
|
removeIconTemplate;
|
|
loadingIconTemplate;
|
|
clearIconTemplate;
|
|
dropdownIconTemplate;
|
|
value;
|
|
_suggestions = signal(null);
|
|
onModelChange = () => { };
|
|
onModelTouched = () => { };
|
|
timeout;
|
|
overlayVisible;
|
|
suggestionsUpdated;
|
|
highlightOption;
|
|
highlightOptionChanged;
|
|
focused = false;
|
|
_filled;
|
|
get filled() {
|
|
return this._filled;
|
|
}
|
|
set filled(value) {
|
|
this._filled = value;
|
|
}
|
|
loading;
|
|
scrollHandler;
|
|
listId;
|
|
searchTimeout;
|
|
dirty = false;
|
|
modelValue = signal(null);
|
|
focusedMultipleOptionIndex = signal(-1);
|
|
focusedOptionIndex = signal(-1);
|
|
visibleOptions = computed(() => {
|
|
return this.group ? this.flatOptions(this._suggestions()) : this._suggestions() || [];
|
|
});
|
|
inputValue = computed(() => {
|
|
const modelValue = this.modelValue();
|
|
const selectedOption = this.optionValueSelected ? (this.suggestions || []).find((item) => ObjectUtils.resolveFieldData(item, this.optionValue) === modelValue) : modelValue;
|
|
if (modelValue) {
|
|
if (typeof modelValue === 'object' || this.optionValueSelected) {
|
|
const label = this.getOptionLabel(selectedOption);
|
|
return label != null ? label : modelValue;
|
|
}
|
|
else {
|
|
return modelValue;
|
|
}
|
|
}
|
|
else {
|
|
return '';
|
|
}
|
|
});
|
|
get focusedMultipleOptionId() {
|
|
return this.focusedMultipleOptionIndex() !== -1 ? `${this.id}_multiple_option_${this.focusedMultipleOptionIndex()}` : null;
|
|
}
|
|
get focusedOptionId() {
|
|
return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
|
|
}
|
|
get containerClass() {
|
|
return {
|
|
'p-autocomplete p-component p-inputwrapper': true,
|
|
'p-disabled': this.disabled,
|
|
'p-focus': this.focused,
|
|
'p-autocomplete-dd': this.dropdown,
|
|
'p-autocomplete-multiple': this.multiple,
|
|
'p-inputwrapper-focus': this.focused,
|
|
'p-overlay-open': this.overlayVisible
|
|
};
|
|
}
|
|
get multiContainerClass() {
|
|
return { 'p-autocomplete-multiple-container p-component p-inputtext': true, 'p-variant-filled': this.variant === 'filled' || this.config.inputStyle() === 'filled' };
|
|
}
|
|
get panelClass() {
|
|
return {
|
|
'p-autocomplete-panel p-component': true,
|
|
'p-input-filled': this.config.inputStyle() === 'filled',
|
|
'p-ripple-disabled': this.config.ripple === false
|
|
};
|
|
}
|
|
get inputClass() {
|
|
return {
|
|
'p-autocomplete-input p-inputtext p-component': !this.multiple,
|
|
'p-autocomplete-dd-input': this.dropdown,
|
|
'p-variant-filled': this.variant === 'filled' || this.config.inputStyle() === 'filled'
|
|
};
|
|
}
|
|
get searchResultMessageText() {
|
|
return ObjectUtils.isNotEmpty(this.visibleOptions()) && this.overlayVisible ? this.searchMessageText.replaceAll('{0}', this.visibleOptions().length) : this.emptySearchMessageText;
|
|
}
|
|
get searchMessageText() {
|
|
return this.searchMessage || this.config.translation.searchMessage || '';
|
|
}
|
|
get emptySearchMessageText() {
|
|
return this.emptyMessage || this.config.translation.emptySearchMessage || '';
|
|
}
|
|
get selectionMessageText() {
|
|
return this.selectionMessage || this.config.translation.selectionMessage || '';
|
|
}
|
|
get emptySelectionMessageText() {
|
|
return this.emptySelectionMessage || this.config.translation.emptySelectionMessage || '';
|
|
}
|
|
get selectedMessageText() {
|
|
return this.hasSelectedOption() ? this.selectionMessageText.replaceAll('{0}', this.multiple ? this.modelValue().length : '1') : this.emptySelectionMessageText;
|
|
}
|
|
get ariaSetSize() {
|
|
return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;
|
|
}
|
|
get listLabel() {
|
|
return this.config.getTranslation(TranslationKeys.ARIA)['listLabel'];
|
|
}
|
|
get virtualScrollerDisabled() {
|
|
return !this.virtualScroll;
|
|
}
|
|
get optionValueSelected() {
|
|
return typeof this.modelValue() === 'string' && this.optionValue;
|
|
}
|
|
constructor(document, el, renderer, cd, config, overlayService, zone) {
|
|
this.document = document;
|
|
this.el = el;
|
|
this.renderer = renderer;
|
|
this.cd = cd;
|
|
this.config = config;
|
|
this.overlayService = overlayService;
|
|
this.zone = zone;
|
|
effect(() => {
|
|
this.filled = ObjectUtils.isNotEmpty(this.modelValue());
|
|
});
|
|
}
|
|
ngOnInit() {
|
|
this.id = this.id || UniqueComponentId();
|
|
this.cd.detectChanges();
|
|
}
|
|
ngAfterViewChecked() {
|
|
//Use timeouts as since Angular 4.2, AfterViewChecked is broken and not called after panel is updated
|
|
if (this.suggestionsUpdated && this.overlayViewChild) {
|
|
this.zone.runOutsideAngular(() => {
|
|
setTimeout(() => {
|
|
if (this.overlayViewChild) {
|
|
this.overlayViewChild.alignOverlay();
|
|
}
|
|
}, 1);
|
|
this.suggestionsUpdated = false;
|
|
});
|
|
}
|
|
}
|
|
ngAfterContentInit() {
|
|
this.templates.forEach((item) => {
|
|
switch (item.getType()) {
|
|
case 'item':
|
|
this.itemTemplate = item.template;
|
|
break;
|
|
case 'group':
|
|
this.groupTemplate = item.template;
|
|
break;
|
|
case 'selectedItem':
|
|
this.selectedItemTemplate = item.template;
|
|
break;
|
|
case 'header':
|
|
this.headerTemplate = item.template;
|
|
break;
|
|
case 'empty':
|
|
this.emptyTemplate = item.template;
|
|
break;
|
|
case 'footer':
|
|
this.footerTemplate = item.template;
|
|
break;
|
|
case 'loader':
|
|
this.loaderTemplate = item.template;
|
|
break;
|
|
case 'removetokenicon':
|
|
this.removeIconTemplate = item.template;
|
|
break;
|
|
case 'loadingicon':
|
|
this.loadingIconTemplate = item.template;
|
|
break;
|
|
case 'clearicon':
|
|
this.clearIconTemplate = item.template;
|
|
break;
|
|
case 'dropdownicon':
|
|
this.dropdownIconTemplate = item.template;
|
|
break;
|
|
default:
|
|
this.itemTemplate = item.template;
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
handleSuggestionsChange() {
|
|
if (this.loading) {
|
|
this._suggestions() ? this.show() : !!this.emptyTemplate ? this.show() : this.hide();
|
|
const focusedOptionIndex = this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
|
this.focusedOptionIndex.set(focusedOptionIndex);
|
|
this.suggestionsUpdated = true;
|
|
this.loading = false;
|
|
this.cd.markForCheck();
|
|
}
|
|
}
|
|
flatOptions(options) {
|
|
return (options || []).reduce((result, option, index) => {
|
|
result.push({ optionGroup: option, group: true, index });
|
|
const optionGroupChildren = this.getOptionGroupChildren(option);
|
|
optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));
|
|
return result;
|
|
}, []);
|
|
}
|
|
isOptionGroup(option) {
|
|
return this.optionGroupLabel && option.optionGroup && option.group;
|
|
}
|
|
findFirstOptionIndex() {
|
|
return this.visibleOptions().findIndex((option) => this.isValidOption(option));
|
|
}
|
|
findLastOptionIndex() {
|
|
return ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));
|
|
}
|
|
findFirstFocusedOptionIndex() {
|
|
const selectedIndex = this.findSelectedOptionIndex();
|
|
return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
|
|
}
|
|
findLastFocusedOptionIndex() {
|
|
const selectedIndex = this.findSelectedOptionIndex();
|
|
return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
|
|
}
|
|
findSelectedOptionIndex() {
|
|
return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
|
}
|
|
findNextOptionIndex(index) {
|
|
const matchedOptionIndex = index < this.visibleOptions().length - 1
|
|
? this.visibleOptions()
|
|
.slice(index + 1)
|
|
.findIndex((option) => this.isValidOption(option))
|
|
: -1;
|
|
return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;
|
|
}
|
|
findPrevOptionIndex(index) {
|
|
const matchedOptionIndex = index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;
|
|
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
|
}
|
|
isValidSelectedOption(option) {
|
|
return this.isValidOption(option) && this.isSelected(option);
|
|
}
|
|
isValidOption(option) {
|
|
return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));
|
|
}
|
|
isOptionDisabled(option) {
|
|
return this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : false;
|
|
}
|
|
isSelected(option) {
|
|
if (this.multiple) {
|
|
return this.unique ? this.modelValue()?.find((model) => ObjectUtils.equals(model, this.getOptionValue(option), this.equalityKey())) : false;
|
|
}
|
|
return ObjectUtils.equals(this.modelValue(), this.getOptionValue(option), this.equalityKey());
|
|
}
|
|
isOptionMatched(option, value) {
|
|
return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.searchLocale) === value.toLocaleLowerCase(this.searchLocale);
|
|
}
|
|
isInputClicked(event) {
|
|
return event.target === this.inputEL.nativeElement;
|
|
}
|
|
isDropdownClicked(event) {
|
|
return this.dropdownButton?.nativeElement ? event.target === this.dropdownButton.nativeElement || this.dropdownButton.nativeElement.contains(event.target) : false;
|
|
}
|
|
equalityKey() {
|
|
return this.dataKey; // TODO: The 'optionValue' properties can be added.
|
|
}
|
|
onContainerClick(event) {
|
|
if (this.disabled || this.loading || this.isInputClicked(event) || this.isDropdownClicked(event)) {
|
|
return;
|
|
}
|
|
if (!this.overlayViewChild || !this.overlayViewChild.overlayViewChild?.nativeElement.contains(event.target)) {
|
|
DomHandler.focus(this.inputEL.nativeElement);
|
|
}
|
|
}
|
|
handleDropdownClick(event) {
|
|
let query = undefined;
|
|
if (this.overlayVisible) {
|
|
this.hide(true);
|
|
}
|
|
else {
|
|
DomHandler.focus(this.inputEL.nativeElement);
|
|
query = this.inputEL.nativeElement.value;
|
|
if (this.dropdownMode === 'blank')
|
|
this.search(event, '', 'dropdown');
|
|
else if (this.dropdownMode === 'current')
|
|
this.search(event, query, 'dropdown');
|
|
}
|
|
this.onDropdownClick.emit({ originalEvent: event, query });
|
|
}
|
|
onInput(event) {
|
|
if (this.searchTimeout) {
|
|
clearTimeout(this.searchTimeout);
|
|
}
|
|
let query = event.target.value;
|
|
if (this.maxlength !== null) {
|
|
query = query.split('').slice(0, this.maxlength).join('');
|
|
}
|
|
if (!this.multiple && !this.forceSelection) {
|
|
this.updateModel(query);
|
|
}
|
|
if (query.length === 0 && !this.multiple) {
|
|
this.onClear.emit();
|
|
setTimeout(() => {
|
|
this.hide();
|
|
}, this.delay / 2);
|
|
}
|
|
else {
|
|
if (query.length >= this.minLength) {
|
|
this.focusedOptionIndex.set(-1);
|
|
this.searchTimeout = setTimeout(() => {
|
|
this.search(event, query, 'input');
|
|
}, this.delay);
|
|
}
|
|
else {
|
|
this.hide();
|
|
}
|
|
}
|
|
}
|
|
onInputChange(event) {
|
|
if (this.forceSelection) {
|
|
let valid = false;
|
|
if (this.visibleOptions()) {
|
|
const matchedValue = this.visibleOptions().find((option) => this.isOptionMatched(option, this.inputEL.nativeElement.value || ''));
|
|
if (matchedValue !== undefined) {
|
|
valid = true;
|
|
!this.isSelected(matchedValue) && this.onOptionSelect(event, matchedValue);
|
|
}
|
|
}
|
|
if (!valid) {
|
|
this.inputEL.nativeElement.value = '';
|
|
!this.multiple && this.updateModel(null);
|
|
}
|
|
}
|
|
}
|
|
onInputFocus(event) {
|
|
if (this.disabled) {
|
|
// For ScreenReaders
|
|
return;
|
|
}
|
|
if (!this.dirty && this.completeOnFocus) {
|
|
this.search(event, event.target.value, 'focus');
|
|
}
|
|
this.dirty = true;
|
|
this.focused = true;
|
|
const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
|
this.focusedOptionIndex.set(focusedOptionIndex);
|
|
this.overlayVisible && this.scrollInView(this.focusedOptionIndex());
|
|
this.onFocus.emit(event);
|
|
}
|
|
onMultipleContainerFocus(event) {
|
|
if (this.disabled) {
|
|
// For ScreenReaders
|
|
return;
|
|
}
|
|
this.focused = true;
|
|
}
|
|
onMultipleContainerBlur(event) {
|
|
this.focusedMultipleOptionIndex.set(-1);
|
|
this.focused = false;
|
|
}
|
|
onMultipleContainerKeyDown(event) {
|
|
if (this.disabled) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
switch (event.code) {
|
|
case 'ArrowLeft':
|
|
this.onArrowLeftKeyOnMultiple(event);
|
|
break;
|
|
case 'ArrowRight':
|
|
this.onArrowRightKeyOnMultiple(event);
|
|
break;
|
|
case 'Backspace':
|
|
this.onBackspaceKeyOnMultiple(event);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
onInputBlur(event) {
|
|
this.dirty = false;
|
|
this.focused = false;
|
|
this.focusedOptionIndex.set(-1);
|
|
this.onModelTouched();
|
|
this.onBlur.emit(event);
|
|
}
|
|
onInputPaste(event) {
|
|
this.onKeyDown(event);
|
|
}
|
|
onInputKeyUp(event) {
|
|
this.onKeyUp.emit(event);
|
|
}
|
|
onKeyDown(event) {
|
|
if (this.disabled) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
switch (event.code) {
|
|
case 'ArrowDown':
|
|
this.onArrowDownKey(event);
|
|
break;
|
|
case 'ArrowUp':
|
|
this.onArrowUpKey(event);
|
|
break;
|
|
case 'ArrowLeft':
|
|
this.onArrowLeftKey(event);
|
|
break;
|
|
case 'ArrowRight':
|
|
this.onArrowRightKey(event);
|
|
break;
|
|
case 'Home':
|
|
this.onHomeKey(event);
|
|
break;
|
|
case 'End':
|
|
this.onEndKey(event);
|
|
break;
|
|
case 'PageDown':
|
|
this.onPageDownKey(event);
|
|
break;
|
|
case 'PageUp':
|
|
this.onPageUpKey(event);
|
|
break;
|
|
case 'Enter':
|
|
case 'NumpadEnter':
|
|
this.onEnterKey(event);
|
|
break;
|
|
case 'Escape':
|
|
this.onEscapeKey(event);
|
|
break;
|
|
case 'Tab':
|
|
this.onTabKey(event);
|
|
break;
|
|
case 'Backspace':
|
|
this.onBackspaceKey(event);
|
|
break;
|
|
case 'ShiftLeft':
|
|
case 'ShiftRight':
|
|
//NOOP
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
onArrowDownKey(event) {
|
|
if (!this.overlayVisible) {
|
|
return;
|
|
}
|
|
const optionIndex = this.focusedOptionIndex() !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex()) : this.findFirstFocusedOptionIndex();
|
|
this.changeFocusedOptionIndex(event, optionIndex);
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
onArrowUpKey(event) {
|
|
if (!this.overlayVisible) {
|
|
return;
|
|
}
|
|
if (event.altKey) {
|
|
if (this.focusedOptionIndex() !== -1) {
|
|
this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
|
|
}
|
|
this.overlayVisible && this.hide();
|
|
event.preventDefault();
|
|
}
|
|
else {
|
|
const optionIndex = this.focusedOptionIndex() !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex()) : this.findLastFocusedOptionIndex();
|
|
this.changeFocusedOptionIndex(event, optionIndex);
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
onArrowLeftKey(event) {
|
|
const target = event.currentTarget;
|
|
this.focusedOptionIndex.set(-1);
|
|
if (this.multiple) {
|
|
if (ObjectUtils.isEmpty(target.value) && this.hasSelectedOption()) {
|
|
DomHandler.focus(this.multiContainerEL.nativeElement);
|
|
this.focusedMultipleOptionIndex.set(this.modelValue().length);
|
|
}
|
|
else {
|
|
event.stopPropagation(); // To prevent onArrowLeftKeyOnMultiple method
|
|
}
|
|
}
|
|
}
|
|
onArrowRightKey(event) {
|
|
this.focusedOptionIndex.set(-1);
|
|
this.multiple && event.stopPropagation(); // To prevent onArrowRightKeyOnMultiple method
|
|
}
|
|
onHomeKey(event) {
|
|
const { currentTarget } = event;
|
|
const len = currentTarget.value.length;
|
|
currentTarget.setSelectionRange(0, event.shiftKey ? len : 0);
|
|
this.focusedOptionIndex.set(-1);
|
|
event.preventDefault();
|
|
}
|
|
onEndKey(event) {
|
|
const { currentTarget } = event;
|
|
const len = currentTarget.value.length;
|
|
currentTarget.setSelectionRange(event.shiftKey ? 0 : len, len);
|
|
this.focusedOptionIndex.set(-1);
|
|
event.preventDefault();
|
|
}
|
|
onPageDownKey(event) {
|
|
this.scrollInView(this.visibleOptions().length - 1);
|
|
event.preventDefault();
|
|
}
|
|
onPageUpKey(event) {
|
|
this.scrollInView(0);
|
|
event.preventDefault();
|
|
}
|
|
onEnterKey(event) {
|
|
if (!this.overlayVisible) {
|
|
this.onArrowDownKey(event);
|
|
}
|
|
else {
|
|
if (this.focusedOptionIndex() !== -1) {
|
|
this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
|
|
}
|
|
this.hide();
|
|
}
|
|
event.preventDefault();
|
|
}
|
|
onEscapeKey(event) {
|
|
this.overlayVisible && this.hide(true);
|
|
event.preventDefault();
|
|
}
|
|
onTabKey(event) {
|
|
if (this.focusedOptionIndex() !== -1) {
|
|
this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
|
|
}
|
|
this.overlayVisible && this.hide();
|
|
}
|
|
onBackspaceKey(event) {
|
|
if (this.multiple) {
|
|
if (ObjectUtils.isNotEmpty(this.modelValue()) && !this.inputEL.nativeElement.value) {
|
|
const removedValue = this.modelValue()[this.modelValue().length - 1];
|
|
const newValue = this.modelValue().slice(0, -1);
|
|
this.updateModel(newValue);
|
|
this.onUnselect.emit({ originalEvent: event, value: removedValue });
|
|
}
|
|
event.stopPropagation(); // To prevent onBackspaceKeyOnMultiple method
|
|
}
|
|
if (!this.multiple && this.showClear && this.findSelectedOptionIndex() != -1) {
|
|
this.clear();
|
|
}
|
|
}
|
|
onArrowLeftKeyOnMultiple(event) {
|
|
const optionIndex = this.focusedMultipleOptionIndex() < 1 ? 0 : this.focusedMultipleOptionIndex() - 1;
|
|
this.focusedMultipleOptionIndex.set(optionIndex);
|
|
}
|
|
onArrowRightKeyOnMultiple(event) {
|
|
let optionIndex = this.focusedMultipleOptionIndex();
|
|
optionIndex++;
|
|
this.focusedMultipleOptionIndex.set(optionIndex);
|
|
if (optionIndex > this.modelValue().length - 1) {
|
|
this.focusedMultipleOptionIndex.set(-1);
|
|
DomHandler.focus(this.inputEL.nativeElement);
|
|
}
|
|
}
|
|
onBackspaceKeyOnMultiple(event) {
|
|
if (this.focusedMultipleOptionIndex() !== -1) {
|
|
this.removeOption(event, this.focusedMultipleOptionIndex());
|
|
}
|
|
}
|
|
onOptionSelect(event, option, isHide = true) {
|
|
const value = this.getOptionValue(option);
|
|
if (this.multiple) {
|
|
this.inputEL.nativeElement.value = '';
|
|
if (!this.isSelected(option)) {
|
|
this.updateModel([...(this.modelValue() || []), value]);
|
|
}
|
|
}
|
|
else {
|
|
this.updateModel(value);
|
|
}
|
|
this.onSelect.emit({ originalEvent: event, value: option });
|
|
isHide && this.hide(true);
|
|
}
|
|
onOptionMouseEnter(event, index) {
|
|
if (this.focusOnHover) {
|
|
this.changeFocusedOptionIndex(event, index);
|
|
}
|
|
}
|
|
search(event, query, source) {
|
|
//allow empty string but not undefined or null
|
|
if (query === undefined || query === null) {
|
|
return;
|
|
}
|
|
//do not search blank values on input change
|
|
if (source === 'input' && query.trim().length === 0) {
|
|
return;
|
|
}
|
|
this.loading = true;
|
|
this.completeMethod.emit({ originalEvent: event, query });
|
|
}
|
|
removeOption(event, index) {
|
|
event.stopPropagation();
|
|
const removedOption = this.modelValue()[index];
|
|
const value = this.modelValue()
|
|
.filter((_, i) => i !== index)
|
|
.map((option) => this.getOptionValue(option));
|
|
this.updateModel(value);
|
|
this.onUnselect.emit({ originalEvent: event, value: removedOption });
|
|
DomHandler.focus(this.inputEL.nativeElement);
|
|
}
|
|
updateModel(value) {
|
|
this.value = value;
|
|
this.modelValue.set(value);
|
|
this.onModelChange(value);
|
|
this.updateInputValue();
|
|
this.cd.markForCheck();
|
|
}
|
|
updateInputValue() {
|
|
if (this.inputEL && this.inputEL.nativeElement) {
|
|
if (!this.multiple) {
|
|
this.inputEL.nativeElement.value = this.inputValue();
|
|
}
|
|
else {
|
|
this.inputEL.nativeElement.value = '';
|
|
}
|
|
}
|
|
}
|
|
autoUpdateModel() {
|
|
if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption()) {
|
|
const focusedOptionIndex = this.findFirstFocusedOptionIndex();
|
|
this.focusedOptionIndex.set(focusedOptionIndex);
|
|
this.onOptionSelect(null, this.visibleOptions()[this.focusedOptionIndex()], false);
|
|
}
|
|
}
|
|
scrollInView(index = -1) {
|
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
|
if (this.itemsViewChild && this.itemsViewChild.nativeElement) {
|
|
const element = DomHandler.findSingle(this.itemsViewChild.nativeElement, `li[id="${id}"]`);
|
|
if (element) {
|
|
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
}
|
|
else if (!this.virtualScrollerDisabled) {
|
|
setTimeout(() => {
|
|
this.virtualScroll && this.scroller?.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex());
|
|
}, 0);
|
|
}
|
|
}
|
|
}
|
|
changeFocusedOptionIndex(event, index) {
|
|
if (this.focusedOptionIndex() !== index) {
|
|
this.focusedOptionIndex.set(index);
|
|
this.scrollInView();
|
|
if (this.selectOnFocus) {
|
|
this.onOptionSelect(event, this.visibleOptions()[index], false);
|
|
}
|
|
}
|
|
}
|
|
show(isFocus = false) {
|
|
this.dirty = true;
|
|
this.overlayVisible = true;
|
|
const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
|
this.focusedOptionIndex.set(focusedOptionIndex);
|
|
isFocus && DomHandler.focus(this.inputEL.nativeElement);
|
|
if (isFocus) {
|
|
DomHandler.focus(this.inputEL.nativeElement);
|
|
}
|
|
this.onShow.emit();
|
|
this.cd.markForCheck();
|
|
}
|
|
hide(isFocus = false) {
|
|
const _hide = () => {
|
|
this.dirty = isFocus;
|
|
this.overlayVisible = false;
|
|
this.focusedOptionIndex.set(-1);
|
|
isFocus && DomHandler.focus(this.inputEL.nativeElement);
|
|
this.onHide.emit();
|
|
this.cd.markForCheck();
|
|
};
|
|
setTimeout(() => {
|
|
_hide();
|
|
}, 0); // For ScreenReaders
|
|
}
|
|
clear() {
|
|
this.updateModel(null);
|
|
this.inputEL.nativeElement.value = '';
|
|
this.onClear.emit();
|
|
}
|
|
writeValue(value) {
|
|
this.value = value;
|
|
this.modelValue.set(value);
|
|
this.updateInputValue();
|
|
this.cd.markForCheck();
|
|
}
|
|
hasSelectedOption() {
|
|
return ObjectUtils.isNotEmpty(this.modelValue());
|
|
}
|
|
getAriaPosInset(index) {
|
|
return ((this.optionGroupLabel
|
|
? index -
|
|
this.visibleOptions()
|
|
.slice(0, index)
|
|
.filter((option) => this.isOptionGroup(option)).length
|
|
: index) + 1);
|
|
}
|
|
getOptionLabel(option) {
|
|
return this.field || this.optionLabel ? ObjectUtils.resolveFieldData(option, this.field || this.optionLabel) : option && option.label != undefined ? option.label : option;
|
|
}
|
|
getOptionValue(option) {
|
|
return this.optionValue ? ObjectUtils.resolveFieldData(option, this.optionValue) : option && option.value != undefined ? option.value : option;
|
|
}
|
|
getOptionIndex(index, scrollerOptions) {
|
|
return this.virtualScrollerDisabled ? index : scrollerOptions && scrollerOptions.getItemOptions(index)['index'];
|
|
}
|
|
getOptionGroupLabel(optionGroup) {
|
|
return this.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel) : optionGroup && optionGroup.label != undefined ? optionGroup.label : optionGroup;
|
|
}
|
|
getOptionGroupChildren(optionGroup) {
|
|
return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
|
|
}
|
|
registerOnChange(fn) {
|
|
this.onModelChange = fn;
|
|
}
|
|
registerOnTouched(fn) {
|
|
this.onModelTouched = fn;
|
|
}
|
|
setDisabledState(val) {
|
|
this.disabled = val;
|
|
this.cd.markForCheck();
|
|
}
|
|
onOverlayAnimationStart(event) {
|
|
if (event.toState === 'visible') {
|
|
this.itemsWrapper = DomHandler.findSingle(this.overlayViewChild.overlayViewChild?.nativeElement, this.virtualScroll ? '.p-scroller' : '.p-autocomplete-panel');
|
|
if (this.virtualScroll) {
|
|
this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
|
|
this.scroller.viewInit();
|
|
}
|
|
if (this.visibleOptions() && this.visibleOptions().length) {
|
|
if (this.virtualScroll) {
|
|
const selectedIndex = this.modelValue() ? this.focusedOptionIndex() : -1;
|
|
if (selectedIndex !== -1) {
|
|
this.scroller?.scrollToIndex(selectedIndex);
|
|
}
|
|
}
|
|
else {
|
|
let selectedListItem = DomHandler.findSingle(this.itemsWrapper, '.p-autocomplete-item.p-highlight');
|
|
if (selectedListItem) {
|
|
selectedListItem.scrollIntoView({ block: 'nearest', inline: 'center' });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ngOnDestroy() {
|
|
if (this.scrollHandler) {
|
|
this.scrollHandler.destroy();
|
|
this.scrollHandler = null;
|
|
}
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: AutoComplete, deps: [{ token: DOCUMENT }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.PrimeNGConfig }, { token: i1.OverlayService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "17.3.7", type: AutoComplete, selector: "p-autoComplete", inputs: { minLength: ["minLength", "minLength", numberAttribute], delay: ["delay", "delay", numberAttribute], style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", inputStyle: "inputStyle", inputId: "inputId", inputStyleClass: "inputStyleClass", placeholder: "placeholder", readonly: ["readonly", "readonly", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], scrollHeight: "scrollHeight", lazy: ["lazy", "lazy", booleanAttribute], virtualScroll: ["virtualScroll", "virtualScroll", booleanAttribute], virtualScrollItemSize: ["virtualScrollItemSize", "virtualScrollItemSize", numberAttribute], virtualScrollOptions: "virtualScrollOptions", maxlength: ["maxlength", "maxlength", (value) => numberAttribute(value, null)], name: "name", required: ["required", "required", booleanAttribute], size: ["size", "size", numberAttribute], appendTo: "appendTo", autoHighlight: ["autoHighlight", "autoHighlight", booleanAttribute], forceSelection: ["forceSelection", "forceSelection", booleanAttribute], type: "type", autoZIndex: ["autoZIndex", "autoZIndex", booleanAttribute], baseZIndex: ["baseZIndex", "baseZIndex", numberAttribute], ariaLabel: "ariaLabel", dropdownAriaLabel: "dropdownAriaLabel", ariaLabelledBy: "ariaLabelledBy", dropdownIcon: "dropdownIcon", unique: ["unique", "unique", booleanAttribute], group: ["group", "group", booleanAttribute], completeOnFocus: ["completeOnFocus", "completeOnFocus", booleanAttribute], showClear: ["showClear", "showClear", booleanAttribute], field: "field", dropdown: ["dropdown", "dropdown", booleanAttribute], showEmptyMessage: ["showEmptyMessage", "showEmptyMessage", booleanAttribute], dropdownMode: "dropdownMode", multiple: ["multiple", "multiple", booleanAttribute], tabindex: ["tabindex", "tabindex", numberAttribute], dataKey: "dataKey", emptyMessage: "emptyMessage", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", autofocus: ["autofocus", "autofocus", booleanAttribute], autocomplete: "autocomplete", optionGroupChildren: "optionGroupChildren", optionGroupLabel: "optionGroupLabel", overlayOptions: "overlayOptions", suggestions: "suggestions", itemSize: "itemSize", optionLabel: "optionLabel", optionValue: "optionValue", id: "id", searchMessage: "searchMessage", emptySelectionMessage: "emptySelectionMessage", selectionMessage: "selectionMessage", autoOptionFocus: ["autoOptionFocus", "autoOptionFocus", booleanAttribute], selectOnFocus: ["selectOnFocus", "selectOnFocus", booleanAttribute], searchLocale: ["searchLocale", "searchLocale", booleanAttribute], optionDisabled: "optionDisabled", focusOnHover: ["focusOnHover", "focusOnHover", booleanAttribute], variant: "variant" }, outputs: { completeMethod: "completeMethod", onSelect: "onSelect", onUnselect: "onUnselect", onFocus: "onFocus", onBlur: "onBlur", onDropdownClick: "onDropdownClick", onClear: "onClear", onKeyUp: "onKeyUp", onShow: "onShow", onHide: "onHide", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "((focused && !disabled) || autofocus) || overlayVisible", "class.p-autocomplete-clearable": "showClear && !disabled" }, classAttribute: "p-element p-inputwrapper" }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerEL", first: true, predicate: ["container"], descendants: true }, { propertyName: "inputEL", first: true, predicate: ["focusInput"], descendants: true }, { propertyName: "multiInputEl", first: true, predicate: ["multiIn"], descendants: true }, { propertyName: "multiContainerEL", first: true, predicate: ["multiContainer"], descendants: true }, { propertyName: "dropdownButton", first: true, predicate: ["ddBtn"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }], ngImport: i0, template: `
|
|
<div #container [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
|
|
<input
|
|
*ngIf="!multiple"
|
|
#focusInput
|
|
pAutoFocus
|
|
[autofocus]="autofocus"
|
|
[ngClass]="inputClass"
|
|
[ngStyle]="inputStyle"
|
|
[class]="inputStyleClass"
|
|
[type]="type"
|
|
[attr.value]="inputValue()"
|
|
[attr.id]="inputId"
|
|
[autocomplete]="autocomplete"
|
|
[required]="required"
|
|
[name]="name"
|
|
aria-autocomplete="list"
|
|
role="combobox"
|
|
[attr.placeholder]="placeholder"
|
|
[attr.size]="size"
|
|
[maxlength]="maxlength"
|
|
[tabindex]="!disabled ? tabindex : -1"
|
|
[readonly]="readonly"
|
|
[disabled]="disabled"
|
|
[attr.aria-label]="ariaLabel"
|
|
[attr.aria-labelledby]="ariaLabelledBy"
|
|
[attr.aria-required]="required"
|
|
[attr.aria-expanded]="overlayVisible ?? false"
|
|
[attr.aria-controls]="overlayVisible ? id + '_list' : null"
|
|
[attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
|
|
(input)="onInput($event)"
|
|
(keydown)="onKeyDown($event)"
|
|
(change)="onInputChange($event)"
|
|
(focus)="onInputFocus($event)"
|
|
(blur)="onInputBlur($event)"
|
|
(paste)="onInputPaste($event)"
|
|
(keyup)="onInputKeyUp($event)"
|
|
/>
|
|
<ng-container *ngIf="filled && !disabled && showClear && !loading">
|
|
<TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" [attr.aria-hidden]="true" />
|
|
<span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()" [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
|
|
</span>
|
|
</ng-container>
|
|
|
|
<ul
|
|
*ngIf="multiple"
|
|
#multiContainer
|
|
[ngClass]="multiContainerClass"
|
|
[tabindex]="-1"
|
|
role="listbox"
|
|
[attr.aria-orientation]="'horizontal'"
|
|
[attr.aria-activedescendant]="focused ? focusedMultipleOptionId : undefined"
|
|
(focus)="onMultipleContainerFocus($event)"
|
|
(blur)="onMultipleContainerBlur($event)"
|
|
(keydown)="onMultipleContainerKeyDown($event)"
|
|
>
|
|
<li
|
|
#token
|
|
*ngFor="let option of modelValue(); let i = index"
|
|
[ngClass]="{ 'p-autocomplete-token': true, 'p-focus': focusedMultipleOptionIndex() === i }"
|
|
[attr.id]="id + '_multiple_option_' + i"
|
|
role="option"
|
|
[attr.aria-label]="getOptionLabel(option)"
|
|
[attr.aria-setsize]="modelValue().length"
|
|
[attr.aria-posinset]="i + 1"
|
|
[attr.aria-selected]="true"
|
|
>
|
|
<ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: option }"></ng-container>
|
|
<span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ getOptionLabel(option) }}</span>
|
|
<span class="p-autocomplete-token-icon" (click)="!readonly ? removeOption($event, i) : ''">
|
|
<TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" [attr.aria-hidden]="true" />
|
|
<span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon" [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="removeIconTemplate"></ng-template>
|
|
</span>
|
|
</span>
|
|
</li>
|
|
<li class="p-autocomplete-input-token" role="option">
|
|
<input
|
|
#focusInput
|
|
pAutoFocus
|
|
[autofocus]="autofocus"
|
|
[ngClass]="inputClass"
|
|
[ngStyle]="inputStyle"
|
|
[class]="inputStyleClass"
|
|
[attr.type]="type"
|
|
[attr.id]="inputId"
|
|
[autocomplete]="autocomplete"
|
|
[required]="required"
|
|
[attr.name]="name"
|
|
role="combobox"
|
|
[attr.placeholder]="!filled ? placeholder : null"
|
|
[attr.size]="size"
|
|
aria-autocomplete="list"
|
|
[maxlength]="maxlength"
|
|
[tabindex]="!disabled ? tabindex : -1"
|
|
[readonly]="readonly"
|
|
[disabled]="disabled"
|
|
[attr.aria-label]="ariaLabel"
|
|
[attr.aria-labelledby]="ariaLabelledBy"
|
|
[attr.aria-required]="required"
|
|
[attr.aria-expanded]="overlayVisible ?? false"
|
|
[attr.aria-controls]="overlayVisible ? id + '_list' : null"
|
|
[attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
|
|
(input)="onInput($event)"
|
|
(keydown)="onKeyDown($event)"
|
|
(change)="onInputChange($event)"
|
|
(focus)="onInputFocus($event)"
|
|
(blur)="onInputBlur($event)"
|
|
(paste)="onInputPaste($event)"
|
|
(keyup)="onInputKeyUp($event)"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
<ng-container *ngIf="loading">
|
|
<SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" [attr.aria-hidden]="true" />
|
|
<span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin " [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
|
|
</span>
|
|
</ng-container>
|
|
<button #ddBtn type="button" pButton [attr.aria-label]="dropdownAriaLabel" class="p-autocomplete-dropdown p-button-icon-only" [disabled]="disabled" pRipple (click)="handleDropdownClick($event)" *ngIf="dropdown" [attr.tabindex]="tabindex">
|
|
<span *ngIf="dropdownIcon" [ngClass]="dropdownIcon" [attr.aria-hidden]="true"></span>
|
|
<ng-container *ngIf="!dropdownIcon">
|
|
<ChevronDownIcon *ngIf="!dropdownIconTemplate" />
|
|
<ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
|
|
</ng-container>
|
|
</button>
|
|
<p-overlay
|
|
#overlay
|
|
[(visible)]="overlayVisible"
|
|
[options]="overlayOptions"
|
|
[target]="'@parent'"
|
|
[appendTo]="appendTo"
|
|
[showTransitionOptions]="showTransitionOptions"
|
|
[hideTransitionOptions]="hideTransitionOptions"
|
|
(onAnimationStart)="onOverlayAnimationStart($event)"
|
|
(onHide)="hide()"
|
|
>
|
|
<div [ngClass]="panelClass" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
|
|
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
|
<p-scroller
|
|
*ngIf="virtualScroll"
|
|
#scroller
|
|
[items]="visibleOptions()"
|
|
[style]="{ height: scrollHeight }"
|
|
[itemSize]="virtualScrollItemSize || _itemSize"
|
|
[autoSize]="true"
|
|
[lazy]="lazy"
|
|
(onLazyLoad)="onLazyLoad.emit($event)"
|
|
[options]="virtualScrollOptions"
|
|
>
|
|
<ng-template pTemplate="content" let-items let-scrollerOptions="options">
|
|
<ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: items, options: scrollerOptions }"></ng-container>
|
|
</ng-template>
|
|
<ng-container *ngIf="loaderTemplate">
|
|
<ng-template pTemplate="loader" let-scrollerOptions="options">
|
|
<ng-container *ngTemplateOutlet="loaderTemplate; context: { options: scrollerOptions }"></ng-container>
|
|
</ng-template>
|
|
</ng-container>
|
|
</p-scroller>
|
|
<ng-container *ngIf="!virtualScroll">
|
|
<ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
|
|
</ng-container>
|
|
|
|
<ng-template #buildInItems let-items let-scrollerOptions="options">
|
|
<ul #items class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" [attr.id]="id + '_list'" [attr.aria-label]="listLabel">
|
|
<ng-template ngFor let-option [ngForOf]="items" let-i="index">
|
|
<ng-container *ngIf="isOptionGroup(option)">
|
|
<li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
|
|
<span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
|
|
<ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
|
|
</li>
|
|
</ng-container>
|
|
<ng-container *ngIf="!isOptionGroup(option)">
|
|
<li
|
|
class="p-autocomplete-item"
|
|
pRipple
|
|
[ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
|
|
[ngClass]="{ 'p-highlight': isSelected(option), 'p-focus': focusedOptionIndex() === getOptionIndex(i, scrollerOptions), 'p-disabled': isOptionDisabled(option) }"
|
|
[attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)"
|
|
role="option"
|
|
[attr.aria-label]="getOptionLabel(option)"
|
|
[attr.aria-selected]="isSelected(option)"
|
|
[attr.aria-disabled]="isOptionDisabled(option)"
|
|
[attr.data-p-focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
|
|
[attr.aria-setsize]="ariaSetSize"
|
|
[attr.aria-posinset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
|
|
(click)="onOptionSelect($event, option)"
|
|
(mouseenter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
|
|
>
|
|
<span *ngIf="!itemTemplate">{{ getOptionLabel(option) }}</span>
|
|
<ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(i) : i }"></ng-container>
|
|
</li>
|
|
</ng-container>
|
|
</ng-template>
|
|
<li *ngIf="!items || (items && items.length === 0 && showEmptyMessage)" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
|
|
<ng-container *ngIf="!emptyTemplate; else empty">
|
|
{{ searchResultMessageText }}
|
|
</ng-container>
|
|
<ng-container #empty *ngTemplateOutlet="emptyTemplate"></ng-container>
|
|
</li>
|
|
</ul>
|
|
</ng-template>
|
|
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
|
|
</div>
|
|
<span role="status" aria-live="polite" class="p-hidden-accessible">
|
|
{{ selectedMessageText }}
|
|
</span>
|
|
</p-overlay>
|
|
</div>
|
|
`, isInline: true, styles: ["@layer primeng{.p-autocomplete{display:inline-flex;position:relative}.p-autocomplete-loader{position:absolute;top:50%;margin-top:-.5rem}.p-autocomplete-dd .p-autocomplete-input{flex:1 1 auto;width:1%}.p-autocomplete-dd .p-autocomplete-input,.p-autocomplete-dd .p-autocomplete-multiple-container{border-top-right-radius:0;border-bottom-right-radius:0}.p-autocomplete-dd .p-autocomplete-dropdown{border-top-left-radius:0;border-bottom-left-radius:0}.p-autocomplete-panel{overflow:auto}.p-autocomplete-items{margin:0;padding:0;list-style-type:none}.p-autocomplete-item{cursor:pointer;white-space:nowrap;position:relative;overflow:hidden}.p-autocomplete-multiple-container{margin:0;padding:0;list-style-type:none;cursor:text;overflow:hidden;display:flex;align-items:center;flex-wrap:wrap}.p-autocomplete-token{width:fit-content;cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-autocomplete-token-icon{display:flex;cursor:pointer}.p-autocomplete-input-token{flex:1 1 auto;display:inline-flex}.p-autocomplete-input-token input{border:0 none;outline:0 none;background-color:transparent;margin:0;padding:0;box-shadow:none;border-radius:0;width:100%}.p-fluid .p-autocomplete{display:flex}.p-fluid .p-autocomplete-dd .p-autocomplete-input{width:1%}.p-autocomplete-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-autocomplete-clearable{position:relative}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(() => i2.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgForOf), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgStyle), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(() => i3.Overlay), selector: "p-overlay", inputs: ["visible", "mode", "style", "styleClass", "contentStyle", "contentStyleClass", "target", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "listener", "responsive", "options"], outputs: ["visibleChange", "onBeforeShow", "onShow", "onBeforeHide", "onHide", "onAnimationStart", "onAnimationDone"] }, { kind: "directive", type: i0.forwardRef(() => i1.PrimeTemplate), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i4.ButtonDirective), selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain"] }, { kind: "directive", type: i0.forwardRef(() => i5.Ripple), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(() => i6.Scroller), selector: "p-scroller", inputs: ["id", "style", "styleClass", "tabindex", "items", "itemSize", "scrollHeight", "scrollWidth", "orientation", "step", "delay", "resizeDelay", "appendOnly", "inline", "lazy", "disabled", "loaderDisabled", "columns", "showSpacer", "showLoader", "numToleratedItems", "loading", "autoSize", "trackBy", "options"], outputs: ["onLazyLoad", "onScroll", "onScrollIndexChange"] }, { kind: "directive", type: i0.forwardRef(() => i7.AutoFocus), selector: "[pAutoFocus]", inputs: ["autofocus"] }, { kind: "component", type: i0.forwardRef(() => TimesCircleIcon), selector: "TimesCircleIcon" }, { kind: "component", type: i0.forwardRef(() => SpinnerIcon), selector: "SpinnerIcon" }, { kind: "component", type: i0.forwardRef(() => TimesIcon), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronDownIcon), selector: "ChevronDownIcon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: AutoComplete, decorators: [{
|
|
type: Component,
|
|
args: [{ selector: 'p-autoComplete', template: `
|
|
<div #container [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
|
|
<input
|
|
*ngIf="!multiple"
|
|
#focusInput
|
|
pAutoFocus
|
|
[autofocus]="autofocus"
|
|
[ngClass]="inputClass"
|
|
[ngStyle]="inputStyle"
|
|
[class]="inputStyleClass"
|
|
[type]="type"
|
|
[attr.value]="inputValue()"
|
|
[attr.id]="inputId"
|
|
[autocomplete]="autocomplete"
|
|
[required]="required"
|
|
[name]="name"
|
|
aria-autocomplete="list"
|
|
role="combobox"
|
|
[attr.placeholder]="placeholder"
|
|
[attr.size]="size"
|
|
[maxlength]="maxlength"
|
|
[tabindex]="!disabled ? tabindex : -1"
|
|
[readonly]="readonly"
|
|
[disabled]="disabled"
|
|
[attr.aria-label]="ariaLabel"
|
|
[attr.aria-labelledby]="ariaLabelledBy"
|
|
[attr.aria-required]="required"
|
|
[attr.aria-expanded]="overlayVisible ?? false"
|
|
[attr.aria-controls]="overlayVisible ? id + '_list' : null"
|
|
[attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
|
|
(input)="onInput($event)"
|
|
(keydown)="onKeyDown($event)"
|
|
(change)="onInputChange($event)"
|
|
(focus)="onInputFocus($event)"
|
|
(blur)="onInputBlur($event)"
|
|
(paste)="onInputPaste($event)"
|
|
(keyup)="onInputKeyUp($event)"
|
|
/>
|
|
<ng-container *ngIf="filled && !disabled && showClear && !loading">
|
|
<TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" [attr.aria-hidden]="true" />
|
|
<span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()" [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
|
|
</span>
|
|
</ng-container>
|
|
|
|
<ul
|
|
*ngIf="multiple"
|
|
#multiContainer
|
|
[ngClass]="multiContainerClass"
|
|
[tabindex]="-1"
|
|
role="listbox"
|
|
[attr.aria-orientation]="'horizontal'"
|
|
[attr.aria-activedescendant]="focused ? focusedMultipleOptionId : undefined"
|
|
(focus)="onMultipleContainerFocus($event)"
|
|
(blur)="onMultipleContainerBlur($event)"
|
|
(keydown)="onMultipleContainerKeyDown($event)"
|
|
>
|
|
<li
|
|
#token
|
|
*ngFor="let option of modelValue(); let i = index"
|
|
[ngClass]="{ 'p-autocomplete-token': true, 'p-focus': focusedMultipleOptionIndex() === i }"
|
|
[attr.id]="id + '_multiple_option_' + i"
|
|
role="option"
|
|
[attr.aria-label]="getOptionLabel(option)"
|
|
[attr.aria-setsize]="modelValue().length"
|
|
[attr.aria-posinset]="i + 1"
|
|
[attr.aria-selected]="true"
|
|
>
|
|
<ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: option }"></ng-container>
|
|
<span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ getOptionLabel(option) }}</span>
|
|
<span class="p-autocomplete-token-icon" (click)="!readonly ? removeOption($event, i) : ''">
|
|
<TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" [attr.aria-hidden]="true" />
|
|
<span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon" [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="removeIconTemplate"></ng-template>
|
|
</span>
|
|
</span>
|
|
</li>
|
|
<li class="p-autocomplete-input-token" role="option">
|
|
<input
|
|
#focusInput
|
|
pAutoFocus
|
|
[autofocus]="autofocus"
|
|
[ngClass]="inputClass"
|
|
[ngStyle]="inputStyle"
|
|
[class]="inputStyleClass"
|
|
[attr.type]="type"
|
|
[attr.id]="inputId"
|
|
[autocomplete]="autocomplete"
|
|
[required]="required"
|
|
[attr.name]="name"
|
|
role="combobox"
|
|
[attr.placeholder]="!filled ? placeholder : null"
|
|
[attr.size]="size"
|
|
aria-autocomplete="list"
|
|
[maxlength]="maxlength"
|
|
[tabindex]="!disabled ? tabindex : -1"
|
|
[readonly]="readonly"
|
|
[disabled]="disabled"
|
|
[attr.aria-label]="ariaLabel"
|
|
[attr.aria-labelledby]="ariaLabelledBy"
|
|
[attr.aria-required]="required"
|
|
[attr.aria-expanded]="overlayVisible ?? false"
|
|
[attr.aria-controls]="overlayVisible ? id + '_list' : null"
|
|
[attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
|
|
(input)="onInput($event)"
|
|
(keydown)="onKeyDown($event)"
|
|
(change)="onInputChange($event)"
|
|
(focus)="onInputFocus($event)"
|
|
(blur)="onInputBlur($event)"
|
|
(paste)="onInputPaste($event)"
|
|
(keyup)="onInputKeyUp($event)"
|
|
/>
|
|
</li>
|
|
</ul>
|
|
<ng-container *ngIf="loading">
|
|
<SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" [attr.aria-hidden]="true" />
|
|
<span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin " [attr.aria-hidden]="true">
|
|
<ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
|
|
</span>
|
|
</ng-container>
|
|
<button #ddBtn type="button" pButton [attr.aria-label]="dropdownAriaLabel" class="p-autocomplete-dropdown p-button-icon-only" [disabled]="disabled" pRipple (click)="handleDropdownClick($event)" *ngIf="dropdown" [attr.tabindex]="tabindex">
|
|
<span *ngIf="dropdownIcon" [ngClass]="dropdownIcon" [attr.aria-hidden]="true"></span>
|
|
<ng-container *ngIf="!dropdownIcon">
|
|
<ChevronDownIcon *ngIf="!dropdownIconTemplate" />
|
|
<ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
|
|
</ng-container>
|
|
</button>
|
|
<p-overlay
|
|
#overlay
|
|
[(visible)]="overlayVisible"
|
|
[options]="overlayOptions"
|
|
[target]="'@parent'"
|
|
[appendTo]="appendTo"
|
|
[showTransitionOptions]="showTransitionOptions"
|
|
[hideTransitionOptions]="hideTransitionOptions"
|
|
(onAnimationStart)="onOverlayAnimationStart($event)"
|
|
(onHide)="hide()"
|
|
>
|
|
<div [ngClass]="panelClass" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
|
|
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
|
<p-scroller
|
|
*ngIf="virtualScroll"
|
|
#scroller
|
|
[items]="visibleOptions()"
|
|
[style]="{ height: scrollHeight }"
|
|
[itemSize]="virtualScrollItemSize || _itemSize"
|
|
[autoSize]="true"
|
|
[lazy]="lazy"
|
|
(onLazyLoad)="onLazyLoad.emit($event)"
|
|
[options]="virtualScrollOptions"
|
|
>
|
|
<ng-template pTemplate="content" let-items let-scrollerOptions="options">
|
|
<ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: items, options: scrollerOptions }"></ng-container>
|
|
</ng-template>
|
|
<ng-container *ngIf="loaderTemplate">
|
|
<ng-template pTemplate="loader" let-scrollerOptions="options">
|
|
<ng-container *ngTemplateOutlet="loaderTemplate; context: { options: scrollerOptions }"></ng-container>
|
|
</ng-template>
|
|
</ng-container>
|
|
</p-scroller>
|
|
<ng-container *ngIf="!virtualScroll">
|
|
<ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
|
|
</ng-container>
|
|
|
|
<ng-template #buildInItems let-items let-scrollerOptions="options">
|
|
<ul #items class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" [attr.id]="id + '_list'" [attr.aria-label]="listLabel">
|
|
<ng-template ngFor let-option [ngForOf]="items" let-i="index">
|
|
<ng-container *ngIf="isOptionGroup(option)">
|
|
<li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
|
|
<span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
|
|
<ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
|
|
</li>
|
|
</ng-container>
|
|
<ng-container *ngIf="!isOptionGroup(option)">
|
|
<li
|
|
class="p-autocomplete-item"
|
|
pRipple
|
|
[ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
|
|
[ngClass]="{ 'p-highlight': isSelected(option), 'p-focus': focusedOptionIndex() === getOptionIndex(i, scrollerOptions), 'p-disabled': isOptionDisabled(option) }"
|
|
[attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)"
|
|
role="option"
|
|
[attr.aria-label]="getOptionLabel(option)"
|
|
[attr.aria-selected]="isSelected(option)"
|
|
[attr.aria-disabled]="isOptionDisabled(option)"
|
|
[attr.data-p-focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
|
|
[attr.aria-setsize]="ariaSetSize"
|
|
[attr.aria-posinset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
|
|
(click)="onOptionSelect($event, option)"
|
|
(mouseenter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
|
|
>
|
|
<span *ngIf="!itemTemplate">{{ getOptionLabel(option) }}</span>
|
|
<ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(i) : i }"></ng-container>
|
|
</li>
|
|
</ng-container>
|
|
</ng-template>
|
|
<li *ngIf="!items || (items && items.length === 0 && showEmptyMessage)" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
|
|
<ng-container *ngIf="!emptyTemplate; else empty">
|
|
{{ searchResultMessageText }}
|
|
</ng-container>
|
|
<ng-container #empty *ngTemplateOutlet="emptyTemplate"></ng-container>
|
|
</li>
|
|
</ul>
|
|
</ng-template>
|
|
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
|
|
</div>
|
|
<span role="status" aria-live="polite" class="p-hidden-accessible">
|
|
{{ selectedMessageText }}
|
|
</span>
|
|
</p-overlay>
|
|
</div>
|
|
`, host: {
|
|
class: 'p-element p-inputwrapper',
|
|
'[class.p-inputwrapper-filled]': 'filled',
|
|
'[class.p-inputwrapper-focus]': '((focused && !disabled) || autofocus) || overlayVisible',
|
|
'[class.p-autocomplete-clearable]': 'showClear && !disabled'
|
|
}, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-autocomplete{display:inline-flex;position:relative}.p-autocomplete-loader{position:absolute;top:50%;margin-top:-.5rem}.p-autocomplete-dd .p-autocomplete-input{flex:1 1 auto;width:1%}.p-autocomplete-dd .p-autocomplete-input,.p-autocomplete-dd .p-autocomplete-multiple-container{border-top-right-radius:0;border-bottom-right-radius:0}.p-autocomplete-dd .p-autocomplete-dropdown{border-top-left-radius:0;border-bottom-left-radius:0}.p-autocomplete-panel{overflow:auto}.p-autocomplete-items{margin:0;padding:0;list-style-type:none}.p-autocomplete-item{cursor:pointer;white-space:nowrap;position:relative;overflow:hidden}.p-autocomplete-multiple-container{margin:0;padding:0;list-style-type:none;cursor:text;overflow:hidden;display:flex;align-items:center;flex-wrap:wrap}.p-autocomplete-token{width:fit-content;cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-autocomplete-token-icon{display:flex;cursor:pointer}.p-autocomplete-input-token{flex:1 1 auto;display:inline-flex}.p-autocomplete-input-token input{border:0 none;outline:0 none;background-color:transparent;margin:0;padding:0;box-shadow:none;border-radius:0;width:100%}.p-fluid .p-autocomplete{display:flex}.p-fluid .p-autocomplete-dd .p-autocomplete-input{width:1%}.p-autocomplete-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-autocomplete-clearable{position:relative}}\n"] }]
|
|
}], ctorParameters: () => [{ type: Document, decorators: [{
|
|
type: Inject,
|
|
args: [DOCUMENT]
|
|
}] }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.PrimeNGConfig }, { type: i1.OverlayService }, { type: i0.NgZone }], propDecorators: { minLength: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], delay: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], style: [{
|
|
type: Input
|
|
}], panelStyle: [{
|
|
type: Input
|
|
}], styleClass: [{
|
|
type: Input
|
|
}], panelStyleClass: [{
|
|
type: Input
|
|
}], inputStyle: [{
|
|
type: Input
|
|
}], inputId: [{
|
|
type: Input
|
|
}], inputStyleClass: [{
|
|
type: Input
|
|
}], placeholder: [{
|
|
type: Input
|
|
}], readonly: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], disabled: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], scrollHeight: [{
|
|
type: Input
|
|
}], lazy: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], virtualScroll: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], virtualScrollItemSize: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], virtualScrollOptions: [{
|
|
type: Input
|
|
}], maxlength: [{
|
|
type: Input,
|
|
args: [{ transform: (value) => numberAttribute(value, null) }]
|
|
}], name: [{
|
|
type: Input
|
|
}], required: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], size: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], appendTo: [{
|
|
type: Input
|
|
}], autoHighlight: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], forceSelection: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], type: [{
|
|
type: Input
|
|
}], autoZIndex: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], baseZIndex: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], ariaLabel: [{
|
|
type: Input
|
|
}], dropdownAriaLabel: [{
|
|
type: Input
|
|
}], ariaLabelledBy: [{
|
|
type: Input
|
|
}], dropdownIcon: [{
|
|
type: Input
|
|
}], unique: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], group: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], completeOnFocus: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], showClear: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], field: [{
|
|
type: Input
|
|
}], dropdown: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], showEmptyMessage: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], dropdownMode: [{
|
|
type: Input
|
|
}], multiple: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], tabindex: [{
|
|
type: Input,
|
|
args: [{ transform: numberAttribute }]
|
|
}], dataKey: [{
|
|
type: Input
|
|
}], emptyMessage: [{
|
|
type: Input
|
|
}], showTransitionOptions: [{
|
|
type: Input
|
|
}], hideTransitionOptions: [{
|
|
type: Input
|
|
}], autofocus: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], autocomplete: [{
|
|
type: Input
|
|
}], optionGroupChildren: [{
|
|
type: Input
|
|
}], optionGroupLabel: [{
|
|
type: Input
|
|
}], overlayOptions: [{
|
|
type: Input
|
|
}], suggestions: [{
|
|
type: Input
|
|
}], itemSize: [{
|
|
type: Input
|
|
}], optionLabel: [{
|
|
type: Input
|
|
}], optionValue: [{
|
|
type: Input
|
|
}], id: [{
|
|
type: Input
|
|
}], searchMessage: [{
|
|
type: Input
|
|
}], emptySelectionMessage: [{
|
|
type: Input
|
|
}], selectionMessage: [{
|
|
type: Input
|
|
}], autoOptionFocus: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], selectOnFocus: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], searchLocale: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], optionDisabled: [{
|
|
type: Input
|
|
}], focusOnHover: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], variant: [{
|
|
type: Input
|
|
}], completeMethod: [{
|
|
type: Output
|
|
}], onSelect: [{
|
|
type: Output
|
|
}], onUnselect: [{
|
|
type: Output
|
|
}], onFocus: [{
|
|
type: Output
|
|
}], onBlur: [{
|
|
type: Output
|
|
}], onDropdownClick: [{
|
|
type: Output
|
|
}], onClear: [{
|
|
type: Output
|
|
}], onKeyUp: [{
|
|
type: Output
|
|
}], onShow: [{
|
|
type: Output
|
|
}], onHide: [{
|
|
type: Output
|
|
}], onLazyLoad: [{
|
|
type: Output
|
|
}], containerEL: [{
|
|
type: ViewChild,
|
|
args: ['container']
|
|
}], inputEL: [{
|
|
type: ViewChild,
|
|
args: ['focusInput']
|
|
}], multiInputEl: [{
|
|
type: ViewChild,
|
|
args: ['multiIn']
|
|
}], multiContainerEL: [{
|
|
type: ViewChild,
|
|
args: ['multiContainer']
|
|
}], dropdownButton: [{
|
|
type: ViewChild,
|
|
args: ['ddBtn']
|
|
}], itemsViewChild: [{
|
|
type: ViewChild,
|
|
args: ['items']
|
|
}], scroller: [{
|
|
type: ViewChild,
|
|
args: ['scroller']
|
|
}], overlayViewChild: [{
|
|
type: ViewChild,
|
|
args: ['overlay']
|
|
}], templates: [{
|
|
type: ContentChildren,
|
|
args: [PrimeTemplate]
|
|
}] } });
|
|
class AutoCompleteModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: AutoCompleteModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.7", ngImport: i0, type: AutoCompleteModule, declarations: [AutoComplete], imports: [CommonModule, OverlayModule, InputTextModule, ButtonModule, SharedModule, RippleModule, ScrollerModule, AutoFocusModule, TimesCircleIcon, SpinnerIcon, TimesIcon, ChevronDownIcon], exports: [AutoComplete, OverlayModule, SharedModule, ScrollerModule, AutoFocusModule] });
|
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: AutoCompleteModule, imports: [CommonModule, OverlayModule, InputTextModule, ButtonModule, SharedModule, RippleModule, ScrollerModule, AutoFocusModule, TimesCircleIcon, SpinnerIcon, TimesIcon, ChevronDownIcon, OverlayModule, SharedModule, ScrollerModule, AutoFocusModule] });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: AutoCompleteModule, decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [CommonModule, OverlayModule, InputTextModule, ButtonModule, SharedModule, RippleModule, ScrollerModule, AutoFocusModule, TimesCircleIcon, SpinnerIcon, TimesIcon, ChevronDownIcon],
|
|
exports: [AutoComplete, OverlayModule, SharedModule, ScrollerModule, AutoFocusModule],
|
|
declarations: [AutoComplete]
|
|
}]
|
|
}] });
|
|
|
|
/**
|
|
* Generated bundle index. Do not edit.
|
|
*/
|
|
|
|
export { AUTOCOMPLETE_VALUE_ACCESSOR, AutoComplete, AutoCompleteModule };
|
|
//# sourceMappingURL=primeng-autocomplete.mjs.map
|