UNPKG

primeng

Version:

PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,

1 lines 135 kB
{"version":3,"file":"primeng-autocomplete.mjs","sources":["../../src/autocomplete/style/autocompletestyle.ts","../../src/autocomplete/autocomplete.ts","../../src/autocomplete/primeng-autocomplete.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { style } from '@primeuix/styles/autocomplete';\nimport { BaseStyle } from 'primeng/base';\n\nconst inlineStyles = {\n root: { position: 'relative' }\n};\n\nconst classes = {\n root: ({ instance }) => [\n 'p-autocomplete p-component p-inputwrapper',\n {\n 'p-invalid': instance.invalid(),\n 'p-focus': instance.focused(),\n 'p-inputwrapper-filled': instance.$filled(),\n 'p-inputwrapper-focus': (instance.focused() && !instance.$disabled()) || instance.autofocus() || instance.overlayVisible(),\n 'p-autocomplete-open': instance.overlayVisible(),\n 'p-autocomplete-fluid': instance.hasFluid\n }\n ],\n pcInputText: 'p-autocomplete-input',\n inputMultiple: ({ instance }) => [\n 'p-autocomplete-input-multiple',\n {\n 'p-disabled': instance.$disabled(),\n 'p-variant-filled': instance.$variant() === 'filled'\n }\n ],\n clearIcon: 'p-autocomplete-clear-icon',\n chipItem: ({ instance, i }) => [\n 'p-autocomplete-chip-item',\n {\n 'p-focus': instance.focusedMultipleOptionIndex() === i\n }\n ],\n pcChip: 'p-autocomplete-chip',\n chipIcon: 'p-autocomplete-chip-icon',\n inputChip: 'p-autocomplete-input-chip',\n loader: 'p-autocomplete-loader',\n dropdown: 'p-autocomplete-dropdown',\n overlay: ({ instance }) => ['p-autocomplete-overlay p-component-overlay p-component', { 'p-input-filled': instance.$variant() === 'filled', 'p-ripple-disabled': instance.config.ripple() === false }],\n listContainer: 'p-autocomplete-list-container',\n list: 'p-autocomplete-list',\n optionGroup: 'p-autocomplete-option-group',\n option: ({ instance, option, i, scrollerOptions }) => ({\n 'p-autocomplete-option': true,\n 'p-autocomplete-option-selected': instance.isSelected(option),\n 'p-focus': instance.focusedOptionIndex() === instance.getOptionIndex(i, scrollerOptions),\n 'p-disabled': instance.isOptionDisabled(option)\n }),\n emptyMessage: 'p-autocomplete-empty-message'\n};\n\n@Injectable()\nexport class AutoCompleteStyle extends BaseStyle {\n name = 'autocomplete';\n\n style = style;\n\n classes = classes;\n\n inlineStyles = inlineStyles;\n}\n\n/**\n *\n * AutoComplete is an input component that provides real-time suggestions while being typed.\n *\n * [Live Demo](https://www.primeng.org/autocomplete/)\n *\n * @module autocompletestyle\n *\n */\nexport enum AutoCompleteClasses {\n /**\n * Class name of the root element\n */\n root = 'p-autocomplete',\n /**\n * Class name of the input element\n */\n pcInputText = 'p-autocomplete-input',\n /**\n * Class name of the input multiple element\n */\n inputMultiple = 'p-autocomplete-input-multiple',\n /**\n * Class name of the chip item element\n */\n chipItem = 'p-autocomplete-chip-item',\n /**\n * Class name of the chip element\n */\n pcChip = 'p-autocomplete-chip',\n /**\n * Class name of the chip icon element\n */\n chipIcon = 'p-autocomplete-chip-icon',\n /**\n * Class name of the input chip element\n */\n inputChip = 'p-autocomplete-input-chip',\n /**\n * Class name of the loader element\n */\n loader = 'p-autocomplete-loader',\n /**\n * Class name of the dropdown element\n */\n dropdown = 'p-autocomplete-dropdown',\n /**\n * Class name of the panel element\n */\n panel = 'p-autocomplete-overlay',\n /**\n * Class name of the list element\n */\n list = 'p-autocomplete-list',\n /**\n * Class name of the option group element\n */\n optionGroup = 'p-autocomplete-option-group',\n /**\n * Class name of the option element\n */\n option = 'p-autocomplete-option',\n /**\n * Class name of the empty message element\n */\n emptyMessage = 'p-autocomplete-empty-message',\n /**\n * Class name of the clear icon\n */\n clearIcon = 'p-autocomplete-clear-icon'\n}\n\nexport interface AutoCompleteStyle extends BaseStyle {}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n effect,\n ElementRef,\n forwardRef,\n HostListener,\n inject,\n InjectionToken,\n input,\n NgModule,\n numberAttribute,\n output,\n signal,\n TemplateRef,\n viewChild,\n ViewEncapsulation\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { ChevronDown as ChevronDownIcon } from '@primeicons/angular/chevron-down';\nimport { Spinner as SpinnerIcon } from '@primeicons/angular/spinner';\nimport { Times as TimesIcon } from '@primeicons/angular/times';\nimport { TimesCircle as TimesCircleIcon } from '@primeicons/angular/times-circle';\nimport { MotionOptions } from '@primeuix/motion';\nimport { equals, findLastIndex, findSingle, focus, isEmpty, isNotEmpty, resolveFieldData, uuid } from '@primeuix/utils';\nimport { OverlayOptions, OverlayService, ScrollerOptions, SharedModule, TranslationKeys } from 'primeng/api';\nimport { AutoFocus } from 'primeng/autofocus';\nimport { PARENT_INSTANCE } from 'primeng/basecomponent';\nimport { BaseInput } from 'primeng/baseinput';\nimport { Bind, BindModule } from 'primeng/bind';\nimport { Chip } from 'primeng/chip';\nimport { ConnectedOverlayScrollHandler } from 'primeng/dom';\nimport { InputText } from 'primeng/inputtext';\nimport { Overlay } from 'primeng/overlay';\nimport { Ripple } from 'primeng/ripple';\nimport { Scroller } from 'primeng/scroller';\nimport { Nullable } from 'primeng/ts-helpers';\nimport {\n AutoCompleteAddEvent,\n AutoCompleteCompleteEvent,\n AutoCompleteDropdownClickEvent,\n AutoCompleteGroupTemplateContext,\n AutoCompleteItemTemplateContext,\n AutoCompleteLazyLoadEvent,\n AutoCompleteLoaderTemplateContext,\n AutoCompletePassThrough,\n AutoCompleteRemoveIconTemplateContext,\n AutoCompleteSelectedItemTemplateContext,\n AutoCompleteSelectEvent,\n AutoCompleteUnselectEvent\n} from 'primeng/types/autocomplete';\nimport type { AppendTo, CSSProperties } from 'primeng/types/shared';\nimport { AutoCompleteStyle } from './style/autocompletestyle';\n\nconst AUTOCOMPLETE_INSTANCE = new InjectionToken<AutoComplete>('AUTOCOMPLETE_INSTANCE');\n\nexport const AUTOCOMPLETE_VALUE_ACCESSOR = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => AutoComplete),\n multi: true\n};\n\n/**\n * AutoComplete is an input component that provides real-time suggestions when being typed.\n * @group Components\n */\n@Component({\n selector: 'p-autocomplete, p-auto-complete',\n standalone: true,\n imports: [NgTemplateOutlet, Overlay, InputText, Ripple, Scroller, AutoFocus, TimesCircleIcon, SpinnerIcon, ChevronDownIcon, Chip, SharedModule, TimesIcon, BindModule],\n template: `\n @if (!multiple()) {\n <input\n #focusInput\n [pAutoFocus]=\"autofocus()\"\n pInputText\n [pt]=\"ptm('pcInputText')\"\n [class]=\"cn(cx('pcInputText'), inputStyleClass())\"\n [style]=\"inputStyle()\"\n [attr.type]=\"type()\"\n [attr.value]=\"inputValue()\"\n [variant]=\"$variant()\"\n [invalid]=\"invalid()\"\n [attr.id]=\"inputId()\"\n [attr.autocomplete]=\"autocomplete()\"\n aria-autocomplete=\"list\"\n role=\"combobox\"\n [attr.placeholder]=\"placeholder()\"\n [attr.name]=\"name()\"\n [attr.minlength]=\"minlength()\"\n [pSize]=\"size()\"\n [attr.min]=\"min()\"\n [attr.max]=\"max()\"\n [attr.pattern]=\"$pattern()\"\n [attr.size]=\"inputSize()\"\n [attr.maxlength]=\"maxlength()\"\n [attr.tabindex]=\"$tabindex()\"\n [attr.required]=\"requiredAttr()\"\n [attr.readonly]=\"readonlyAttr()\"\n [attr.disabled]=\"disabledAttr()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-expanded]=\"overlayVisible()\"\n [attr.aria-controls]=\"getAriaControls()\"\n [attr.aria-activedescendant]=\"getAriaActiveDescendant()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (change)=\"onInputChange($event)\"\n (focus)=\"onInputFocus($event)\"\n (blur)=\"onInputBlur($event)\"\n (paste)=\"onInputPaste($event)\"\n (keyup)=\"onInputKeyUp($event)\"\n [fluid]=\"hasFluid\"\n [pInputTextUnstyled]=\"unstyled()\"\n />\n }\n @if ($showClear()) {\n @if (!clearIconTemplate()) {\n <svg data-p-icon=\"times\" [pBind]=\"ptm('clearIcon')\" [class]=\"cx('clearIcon')\" (click)=\"clear()\" [attr.aria-hidden]=\"true\" />\n } @else {\n <span [pBind]=\"ptm('clearIcon')\" [class]=\"cx('clearIcon')\" (click)=\"clear()\">\n <ng-container [ngTemplateOutlet]=\"clearIconTemplate()!\"></ng-container>\n </span>\n }\n }\n\n @if (multiple()) {\n <ul\n #multiContainer\n [pBind]=\"ptm('inputMultiple')\"\n [class]=\"cx('inputMultiple')\"\n [attr.data-p]=\"inputMultipleDataP\"\n [tabindex]=\"-1\"\n role=\"listbox\"\n [attr.aria-orientation]=\"'horizontal'\"\n [attr.aria-activedescendant]=\"getMultipleAriaActiveDescendant()\"\n (focus)=\"onMultipleContainerFocus($event)\"\n (blur)=\"onMultipleContainerBlur($event)\"\n (keydown)=\"onMultipleContainerKeyDown($event)\"\n >\n @for (option of modelValue(); track getChipTrackKey(option); let i = $index) {\n <li\n #token\n [pBind]=\"ptm('chipItem')\"\n [class]=\"cx('chipItem', { i })\"\n [attr.id]=\"getMultipleOptionId(i)\"\n role=\"option\"\n [attr.aria-label]=\"getOptionLabel(option)\"\n [attr.aria-setsize]=\"modelValue().length\"\n [attr.aria-posinset]=\"i + 1\"\n [attr.aria-selected]=\"true\"\n >\n <p-chip [pt]=\"ptm('pcChip')\" [class]=\"cx('pcChip')\" [label]=\"getChipLabel(option)\" [disabled]=\"$disabled()\" [removable]=\"true\" (onRemove)=\"!readonly() ? removeOption($event, i) : ''\" [unstyled]=\"unstyled()\">\n @if (selectedItemTemplate()) {\n <ng-container [ngTemplateOutlet]=\"selectedItemTemplate()!\" [ngTemplateOutletContext]=\"getSelectedItemContext(option)\"></ng-container>\n }\n <ng-template #removeicon>\n @if (!removeIconTemplate()) {\n <span [pBind]=\"ptm('chipIcon')\" [class]=\"cx('chipIcon')\" (click)=\"!readonly() && !$disabled() ? removeOption($event, i) : ''\">\n <svg data-p-icon=\"times-circle\" [class]=\"cx('chipIcon')\" [attr.aria-hidden]=\"true\" />\n </span>\n } @else {\n <span [pBind]=\"ptm('chipIcon')\" [attr.aria-hidden]=\"true\">\n <ng-container [ngTemplateOutlet]=\"removeIconTemplate()!\" [ngTemplateOutletContext]=\"getRemoveIconContext(i)\"></ng-container>\n </span>\n }\n </ng-template>\n </p-chip>\n </li>\n }\n <li [pBind]=\"ptm('inputChip')\" [class]=\"cx('inputChip')\" role=\"option\">\n <input\n #focusInput\n #multiIn\n [pAutoFocus]=\"autofocus()\"\n [pBind]=\"ptm('input')\"\n [class]=\"cx('pcInputText')\"\n [style]=\"inputStyle()\"\n [attr.type]=\"type()\"\n [attr.id]=\"inputId()\"\n [attr.autocomplete]=\"autocomplete()\"\n [attr.name]=\"name()\"\n [attr.minlength]=\"minlength()\"\n [attr.maxlength]=\"maxlength()\"\n [attr.size]=\"size()\"\n [attr.min]=\"min()\"\n [attr.max]=\"max()\"\n [attr.pattern]=\"$pattern()\"\n role=\"combobox\"\n [attr.placeholder]=\"getMultiplePlaceholder()\"\n aria-autocomplete=\"list\"\n [attr.tabindex]=\"$tabindex()\"\n [attr.required]=\"requiredAttr()\"\n [attr.readonly]=\"readonlyAttr()\"\n [attr.disabled]=\"disabledAttr()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-expanded]=\"overlayVisible()\"\n [attr.aria-controls]=\"getAriaControls()\"\n [attr.aria-activedescendant]=\"getAriaActiveDescendant()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (change)=\"onInputChange($event)\"\n (focus)=\"onInputFocus($event)\"\n (blur)=\"onInputBlur($event)\"\n (paste)=\"onInputPaste($event)\"\n (keyup)=\"onInputKeyUp($event)\"\n />\n </li>\n </ul>\n }\n @if (loading()) {\n @if (!loadingIconTemplate()) {\n <svg data-p-icon=\"spinner\" [pBind]=\"ptm('loader')\" [class]=\"cn(cx('loader'))\" [attr.aria-hidden]=\"true\" />\n } @else {\n <span [pBind]=\"ptm('loader')\" [class]=\"cx('loader')\" [attr.aria-hidden]=\"true\">\n <ng-container [ngTemplateOutlet]=\"loadingIconTemplate()!\"></ng-container>\n </span>\n }\n }\n @if (dropdown()) {\n <button #ddBtn type=\"button\" [pBind]=\"ptm('dropdown')\" [attr.aria-label]=\"dropdownAriaLabel()\" [class]=\"cx('dropdown')\" [disabled]=\"$disabled()\" pRipple (click)=\"handleDropdownClick($event)\" [attr.tabindex]=\"tabindex()\">\n @if (dropdownIcon()) {\n <span [class]=\"dropdownIcon()\" [attr.aria-hidden]=\"true\"></span>\n } @else {\n @if (!dropdownIconTemplate()) {\n <svg data-p-icon=\"chevron-down\" [pBind]=\"ptm('dropdown')\" />\n } @else {\n <ng-container [ngTemplateOutlet]=\"dropdownIconTemplate()!\"></ng-container>\n }\n }\n </button>\n }\n <p-overlay\n #overlay\n [hostAttrSelector]=\"$attrSelector\"\n [visible]=\"overlayVisible()\"\n (visibleChange)=\"overlayVisible.set($event)\"\n [options]=\"overlayOptions()\"\n [target]=\"$overlayTarget\"\n [appendTo]=\"$appendTo()\"\n [unstyled]=\"unstyled()\"\n [pt]=\"ptm('pcOverlay')\"\n [motionOptions]=\"motionOptions()\"\n (onBeforeEnter)=\"onOverlayBeforeEnter()\"\n (onHide)=\"hide()\"\n [attr.data-p]=\"overlayDataP\"\n >\n <ng-template #content>\n <div [pBind]=\"ptm('overlay')\" [class]=\"cn(cx('overlay'), panelStyleClass())\" [style]=\"panelStyle()\">\n @if (headerTemplate()) {\n <ng-container [ngTemplateOutlet]=\"headerTemplate()!\"></ng-container>\n }\n <div [pBind]=\"ptm('listContainer')\" [class]=\"cx('listContainer')\" [style.max-height]=\"getListContainerMaxHeight()\" [tabindex]=\"-1\">\n @if (virtualScroll()) {\n <p-scroller\n #scroller\n [tabindex]=\"-1\"\n [pt]=\"ptm('virtualScroller')\"\n [items]=\"visibleOptions()\"\n [style]=\"scrollerStyle()\"\n [itemSize]=\"virtualScrollItemSize()\"\n [autoSize]=\"true\"\n [lazy]=\"lazy()\"\n (onLazyLoad)=\"onLazyLoad.emit($event)\"\n [options]=\"virtualScrollOptions()\"\n >\n <ng-template #content let-items let-scrollerOptions=\"options\">\n <ng-container [ngTemplateOutlet]=\"buildInItems\" [ngTemplateOutletContext]=\"getBuildInItemsContext(items, scrollerOptions)\"></ng-container>\n </ng-template>\n @if (loaderTemplate()) {\n <ng-template #loader let-scrollerOptions=\"options\">\n <ng-container [ngTemplateOutlet]=\"loaderTemplate()!\" [ngTemplateOutletContext]=\"getLoaderContext(scrollerOptions)\"></ng-container>\n </ng-template>\n }\n </p-scroller>\n } @else {\n <ng-container [ngTemplateOutlet]=\"buildInItems\" [ngTemplateOutletContext]=\"getBuildInItemsContext(visibleOptions(), {})\"></ng-container>\n }\n </div>\n\n <ng-template #buildInItems let-items let-scrollerOptions=\"options\">\n <ul #items [pBind]=\"ptm('list')\" [class]=\"cn(cx('list'), scrollerOptions.contentStyleClass)\" [style]=\"scrollerOptions.contentStyle\" role=\"listbox\" [attr.id]=\"$listId()\" [attr.aria-label]=\"listLabel\">\n @for (option of items; track getOptionValue(option); let i = $index) {\n @if (isOptionGroup(option)) {\n <li [pBind]=\"ptm('optionGroup')\" [attr.id]=\"getOptionElementId(i, scrollerOptions)\" [class]=\"cx('optionGroup')\" [style]=\"getItemStyle(scrollerOptions)\" role=\"option\">\n @if (!groupTemplate()) {\n <span>{{ getOptionGroupLabel(option.optionGroup) }}</span>\n }\n @if (groupTemplate()) {\n <ng-container [ngTemplateOutlet]=\"groupTemplate()!\" [ngTemplateOutletContext]=\"getGroupContext(option.optionGroup)\"></ng-container>\n }\n </li>\n } @else {\n <li\n pRipple\n [pBind]=\"getPTOptions(option, scrollerOptions, i, 'option')\"\n [style]=\"getItemStyle(scrollerOptions)\"\n [class]=\"cx('option', { option, i, scrollerOptions })\"\n [attr.id]=\"getOptionElementId(i, scrollerOptions)\"\n role=\"option\"\n [attr.aria-label]=\"getOptionLabel(option)\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.data-p-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n [attr.data-p-focused]=\"isOptionFocused(i, scrollerOptions)\"\n [attr.aria-setsize]=\"ariaSetSize\"\n [attr.aria-posinset]=\"getAriaPosInset(getOptionIndex(i, scrollerOptions))\"\n (click)=\"onOptionSelect($event, option)\"\n (mouseenter)=\"onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))\"\n >\n @if (!itemTemplate()) {\n <span>{{ getOptionLabel(option) }}</span>\n } @else {\n <ng-container [ngTemplateOutlet]=\"itemTemplate()!\" [ngTemplateOutletContext]=\"getItemContext(option, i, scrollerOptions)\"></ng-container>\n }\n </li>\n }\n }\n @if (shouldShowEmptyMessage(items)) {\n <li [pBind]=\"ptm('emptyMessage')\" [class]=\"cx('emptyMessage')\" [style]=\"getItemStyle(scrollerOptions)\" role=\"option\">\n @if (!emptyTemplate()) {\n {{ searchResultMessageText }}\n } @else {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate()!\"></ng-container>\n }\n </li>\n }\n </ul>\n </ng-template>\n @if (footerTemplate()) {\n <ng-container [ngTemplateOutlet]=\"footerTemplate()!\"></ng-container>\n }\n </div>\n <span role=\"status\" aria-live=\"polite\" class=\"p-hidden-accessible\">\n {{ selectedMessageText }}\n </span>\n </ng-template>\n </p-overlay>\n `,\n providers: [AUTOCOMPLETE_VALUE_ACCESSOR, AutoCompleteStyle, { provide: AUTOCOMPLETE_INSTANCE, useExisting: AutoComplete }, { provide: PARENT_INSTANCE, useExisting: AutoComplete }],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': \"cx('root')\",\n '[style]': \"sx('root')\",\n '[attr.data-p]': 'containerDataP'\n },\n hostDirectives: [Bind]\n})\nexport class AutoComplete extends BaseInput<AutoCompletePassThrough> {\n componentName = 'AutoComplete';\n\n $pcAutoComplete: AutoComplete | undefined = inject(AUTOCOMPLETE_INSTANCE, { optional: true, skipSelf: true }) ?? undefined;\n\n bindDirectiveInstance = inject(Bind, { self: true });\n\n /**\n * Minimum number of characters to initiate a search.\n * @group Props\n */\n minQueryLength = input<number>();\n /**\n * Delay between keystrokes to wait before sending a query.\n * @group Props\n */\n delay = input(300, { transform: numberAttribute });\n /**\n * Inline style of the overlay panel element.\n * @group Props\n */\n panelStyle = input<CSSProperties>();\n /**\n * Style class of the overlay panel element.\n * @group Props\n */\n panelStyleClass = input<string>();\n /**\n * Inline style of the input field.\n * @group Props\n */\n inputStyle = input<CSSProperties>();\n /**\n * Identifier of the focus input to match a label defined for the component.\n * @group Props\n */\n inputId = input<string>();\n /**\n * Inline style of the input field.\n * @group Props\n */\n inputStyleClass = input<string>();\n /**\n * Hint text for the input field.\n * @group Props\n */\n placeholder = input<string>();\n /**\n * When present, it specifies that the input cannot be typed.\n * @group Props\n */\n readonly = input(false, { transform: booleanAttribute });\n /**\n * Maximum height of the suggestions panel.\n * @group Props\n */\n scrollHeight = input('200px');\n /**\n * Defines if data is loaded and interacted with in lazy manner.\n * @group Props\n */\n lazy = input(false, { transform: booleanAttribute });\n /**\n * Whether the data should be loaded on demand during scroll.\n * @group Props\n */\n virtualScroll = input(false, { transform: booleanAttribute });\n /**\n * Height of an item in the list for VirtualScrolling.\n * @group Props\n */\n virtualScrollItemSize = input<number>();\n /**\n * Whether to use the scroller feature. The properties of scroller component can be used like an object in it.\n * @group Props\n */\n virtualScrollOptions = input<ScrollerOptions>();\n /**\n * When enabled, highlights the first item in the list by default.\n * @group Props\n */\n autoHighlight = input(false, { transform: booleanAttribute });\n /**\n * When present, autocomplete clears the manual input if it does not match of the suggestions to force only accepting values from the suggestions.\n * @group Props\n */\n forceSelection = input(false, { transform: booleanAttribute });\n /**\n * Type of the input, defaults to \"text\".\n * @group Props\n */\n type = input('text');\n /**\n * Whether to automatically manage layering.\n * @group Props\n */\n autoZIndex = input(true, { transform: booleanAttribute });\n /**\n * Base zIndex value to use in layering.\n * @group Props\n */\n baseZIndex = input(0, { transform: numberAttribute });\n /**\n * Defines a string that labels the input for accessibility.\n * @group Props\n */\n ariaLabel = input<string>();\n /**\n * Defines a string that labels the dropdown button for accessibility.\n * @group Props\n */\n dropdownAriaLabel = input<string>();\n /**\n * Specifies one or more IDs in the DOM that labels the input field.\n * @group Props\n */\n ariaLabelledBy = input<string>();\n /**\n * Icon class of the dropdown icon.\n * @group Props\n */\n dropdownIcon = input<string>();\n /**\n * Ensures uniqueness of selected items on multiple mode.\n * @group Props\n */\n unique = input(true, { transform: booleanAttribute });\n /**\n * Whether to display options as grouped when nested options are provided.\n * @group Props\n */\n group = input(false, { transform: booleanAttribute });\n /**\n * Whether to run a query when input receives focus.\n * @group Props\n */\n completeOnFocus = input(false, { transform: booleanAttribute });\n /**\n * When enabled, a clear icon is displayed to clear the value.\n * @group Props\n */\n showClear = input(false, { transform: booleanAttribute });\n /**\n * Displays a button next to the input field when enabled.\n * @group Props\n */\n dropdown = input(false, { transform: booleanAttribute });\n /**\n * Whether to show the empty message or not.\n * @group Props\n */\n showEmptyMessage = input(true, { transform: booleanAttribute });\n /**\n * Specifies the behavior dropdown button. Default \"blank\" mode sends an empty string and \"current\" mode sends the input value.\n * @group Props\n */\n dropdownMode = input('blank');\n /**\n * Specifies if multiple values can be selected.\n * @deprecated Use InputTags component instead for chips/tags input functionality.\n * @group Props\n */\n multiple = input(false, { transform: booleanAttribute });\n /**\n * When enabled, the input value is added to the selected items on tab key press when multiple is true and typeahead is false.\n * @deprecated Use InputTags component instead for chips/tags input functionality.\n * @group Props\n */\n addOnTab = input(false, { transform: booleanAttribute });\n /**\n * Index of the element in tabbing order.\n * @group Props\n */\n tabindex = input<number>();\n /**\n * A property to uniquely identify a value in options.\n * @group Props\n */\n dataKey = input<string>();\n /**\n * Text to display when there is no data. Defaults to global value in i18n translation configuration.\n * @group Props\n */\n emptyMessage = input<string>();\n /**\n * When present, it specifies that the component should automatically get focus on load.\n * @group Props\n */\n autofocus = input(false, { transform: booleanAttribute });\n /**\n * Used to define a string that autocomplete attribute the current element.\n * @group Props\n */\n autocomplete = input('off');\n /**\n * Name of the options field of an option group.\n * @group Props\n */\n optionGroupChildren = input<string>('items');\n /**\n * Name of the label field of an option group.\n * @group Props\n */\n optionGroupLabel = input<string>('label');\n /**\n * Options for the overlay element.\n * @group Props\n */\n overlayOptions = input<OverlayOptions>();\n /**\n * An array of suggestions to display.\n * @group Props\n */\n suggestions = input<any[]>([]);\n /**\n * Property name or getter function to use as the label of an option.\n * @group Props\n */\n optionLabel = input<string | ((item: any) => string)>();\n /**\n * Property name or getter function to use as the value of an option.\n * @group Props\n */\n optionValue = input<string | ((item: any) => string)>();\n /**\n * Unique identifier of the component.\n * @group Props\n */\n id = input<string>();\n /**\n * Text to display when the search is active. Defaults to global value in i18n translation configuration.\n * @group Props\n * @defaultValue '{0} results are available'\n */\n searchMessage = input<string>();\n /**\n * Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.\n * @group Props\n * @defaultValue 'No selected item'\n */\n emptySelectionMessage = input<string>();\n /**\n * Text to be displayed in hidden accessible field when options are selected. Defaults to global value in i18n translation configuration.\n * @group Props\n * @defaultValue '{0} items selected'\n */\n selectionMessage = input<string>();\n /**\n * Whether to focus on the first visible or selected element when the overlay panel is shown.\n * @group Props\n */\n autoOptionFocus = input(false, { transform: booleanAttribute });\n /**\n * When enabled, the focused option is selected.\n * @group Props\n */\n selectOnFocus = input(false, { transform: booleanAttribute });\n /**\n * Locale to use in searching. The default locale is the host environment's current locale.\n * @group Props\n */\n searchLocale = input<string | string[]>();\n /**\n * Property name or getter function to use as the disabled flag of an option, defaults to false when not defined.\n * @group Props\n */\n optionDisabled = input<string | ((item: any) => string)>();\n /**\n * When enabled, the hovered option will be focused.\n * @group Props\n */\n focusOnHover = input(true, { transform: booleanAttribute });\n /**\n * Whether typeahead is active or not.\n * @defaultValue true\n * @group Props\n */\n typeahead = input(true, { transform: booleanAttribute });\n /**\n * Whether to add an item on blur event if the input has value and typeahead is false with multiple mode.\n * @deprecated Use InputTags component instead for chips/tags input functionality.\n * @defaultValue false\n * @group Props\n */\n addOnBlur = input(false, { transform: booleanAttribute });\n /**\n * Separator char to add item when typeahead is false and multiple mode is enabled.\n * @deprecated Use InputTags component instead for chips/tags input functionality.\n * @group Props\n */\n separator = input<string | RegExp>();\n /**\n * 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).\n * @defaultValue 'self'\n * @group Props\n */\n appendTo = input<AppendTo>(undefined);\n /**\n * The motion options.\n * @group Props\n */\n motionOptions = input<MotionOptions | undefined>(undefined);\n /**\n * Callback to invoke to search for suggestions.\n * @param {AutoCompleteCompleteEvent} event - Custom complete event.\n * @group Emits\n */\n completeMethod = output<AutoCompleteCompleteEvent>();\n /**\n * Callback to invoke when a suggestion is selected.\n * @param {AutoCompleteSelectEvent} event - custom select event.\n * @group Emits\n */\n onSelect = output<AutoCompleteSelectEvent>();\n /**\n * Callback to invoke when a selected value is removed.\n * @param {AutoCompleteUnselectEvent} event - custom unselect event.\n * @group Emits\n */\n onUnselect = output<AutoCompleteUnselectEvent>();\n /**\n * Callback to invoke when an item is added via addOnBlur or separator features.\n * @param {AutoCompleteAddEvent} event - Custom add event.\n * @group Emits\n */\n onAdd = output<AutoCompleteAddEvent>();\n /**\n * Callback to invoke when the component receives focus.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n onFocus = output<Event>();\n /**\n * Callback to invoke when the component loses focus.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n onBlur = output<Event>();\n /**\n * Callback to invoke to when dropdown button is clicked.\n * @param {AutoCompleteDropdownClickEvent} event - custom dropdown click event.\n * @group Emits\n */\n onDropdownClick = output<AutoCompleteDropdownClickEvent>();\n /**\n * Callback to invoke when clear button is clicked.\n * @group Emits\n */\n onClear = output<void>();\n /**\n * Callback to invoke on input key down.\n * @param {KeyboardEvent} event - Keyboard event.\n * @group Emits\n */\n onInputKeydown = output<KeyboardEvent>();\n /**\n * Callback to invoke on input key up.\n * @param {KeyboardEvent} event - Keyboard event.\n * @group Emits\n */\n onKeyUp = output<KeyboardEvent>();\n /**\n * Callback to invoke on overlay is shown.\n * @group Emits\n */\n onShow = output<void>();\n /**\n * Callback to invoke on overlay is hidden.\n * @group Emits\n */\n onHide = output<void>();\n /**\n * Callback to invoke on lazy load data.\n * @param {AutoCompleteLazyLoadEvent} event - Lazy load event.\n * @group Emits\n */\n onLazyLoad = output<AutoCompleteLazyLoadEvent>();\n\n inputEL = viewChild<ElementRef>('focusInput');\n\n multiInputEl = viewChild<ElementRef>('multiIn');\n\n multiContainerEL = viewChild<ElementRef>('multiContainer');\n\n dropdownButton = viewChild<ElementRef>('ddBtn');\n\n itemsViewChild = viewChild<ElementRef>('items');\n\n scroller = viewChild<Scroller>('scroller');\n\n overlayViewChild = viewChild<Overlay>('overlay');\n\n itemsWrapper: Nullable<HTMLDivElement>;\n\n /**\n * Custom item template.\n * @group Templates\n */\n itemTemplate = contentChild<TemplateRef<AutoCompleteItemTemplateContext>>('item', { descendants: false });\n\n /**\n * Custom empty message template.\n * @group Templates\n */\n emptyTemplate = contentChild<TemplateRef<void>>('empty', { descendants: false });\n\n /**\n * Custom header template.\n * @group Templates\n */\n headerTemplate = contentChild<TemplateRef<void>>('header', { descendants: false });\n\n /**\n * Custom footer template.\n * @group Templates\n */\n footerTemplate = contentChild<TemplateRef<void>>('footer', { descendants: false });\n\n /**\n * Custom selected item template.\n * @group Templates\n */\n selectedItemTemplate = contentChild<TemplateRef<AutoCompleteSelectedItemTemplateContext>>('selecteditem', { descendants: false });\n\n /**\n * Custom group template.\n * @group Templates\n */\n groupTemplate = contentChild<TemplateRef<AutoCompleteGroupTemplateContext>>('group', { descendants: false });\n\n /**\n * Custom loader template.\n * @group Templates\n */\n loaderTemplate = contentChild<TemplateRef<AutoCompleteLoaderTemplateContext>>('loader', { descendants: false });\n\n /**\n * Custom remove icon template.\n * @group Templates\n */\n removeIconTemplate = contentChild<TemplateRef<AutoCompleteRemoveIconTemplateContext>>('removeicon', { descendants: false });\n\n /**\n * Custom loading icon template.\n * @group Templates\n */\n loadingIconTemplate = contentChild<TemplateRef<void>>('loadingicon', { descendants: false });\n\n /**\n * Custom clear icon template.\n * @group Templates\n */\n clearIconTemplate = contentChild<TemplateRef<void>>('clearicon', { descendants: false });\n\n /**\n * Custom dropdown icon template.\n * @group Templates\n */\n dropdownIconTemplate = contentChild<TemplateRef<void>>('dropdownicon', { descendants: false });\n\n @HostListener('click', ['$event'])\n onHostClick(event: MouseEvent) {\n this.onContainerClick(event);\n }\n\n value: any;\n\n timeout: ReturnType<typeof setTimeout> | null = null;\n\n overlayVisible = signal<boolean>(false);\n\n suggestionsUpdated: Nullable<boolean>;\n\n highlightOption: unknown;\n\n highlightOptionChanged: Nullable<boolean>;\n\n focused = signal<boolean>(false);\n\n loading = signal<boolean>(false);\n\n scrollHandler: Nullable<ConnectedOverlayScrollHandler>;\n\n listId: string | undefined;\n\n searchTimeout: ReturnType<typeof setTimeout> | null = null;\n\n dirty: boolean = false;\n\n focusedMultipleOptionIndex = signal<number>(-1);\n\n focusedOptionIndex = signal<number>(-1);\n\n _componentStyle = inject(AutoCompleteStyle);\n\n overlayService = inject(OverlayService);\n\n private _internalId = uuid('pn_id_');\n\n $id = computed(() => this.id() || this._internalId);\n\n $appendTo = computed(() => this.appendTo() || this.config.overlayAppendTo());\n\n get $overlayTarget() {\n return this.el?.nativeElement?.closest('[data-pc-name=\"inputtags\"]') ? '@grandparent' : '@parent';\n }\n\n visibleOptions = computed(() => {\n return this.group() ? this.flatOptions(this.suggestions()) : this.suggestions() || [];\n });\n\n inputValue = computed(() => {\n const modelValue = this.modelValue();\n const selectedOption = this.optionValueSelected ? (this.suggestions() || []).find((option: any) => equals(option, modelValue, this.equalityKey())) : modelValue;\n\n if (isNotEmpty(modelValue)) {\n if (typeof modelValue === 'object' || this.optionValueSelected) {\n const label = this.getOptionLabel(selectedOption);\n\n return label != null ? label : modelValue;\n } else {\n return modelValue;\n }\n } else {\n return '';\n }\n });\n\n $showClear = computed(() => this.$filled() && !this.$disabled() && this.showClear() && !this.loading());\n\n scrollerStyle = computed(() => ({ height: this.scrollHeight() }));\n\n $tabindex = computed(() => (!this.$disabled() ? this.tabindex() : -1));\n\n requiredAttr = computed(() => (this.required() ? '' : undefined));\n\n readonlyAttr = computed(() => (this.readonly() ? '' : undefined));\n\n disabledAttr = computed(() => (this.$disabled() ? '' : undefined));\n\n $listId = computed(() => this.$id() + '_list');\n\n get focusedMultipleOptionId() {\n return this.focusedMultipleOptionIndex() !== -1 ? `${this.$id()}_multiple_option_${this.focusedMultipleOptionIndex()}` : null;\n }\n\n get focusedOptionId() {\n return this.focusedOptionIndex() !== -1 ? `${this.$id()}_${this.focusedOptionIndex()}` : null;\n }\n\n get searchResultMessageText() {\n return isNotEmpty(this.visibleOptions()) && this.overlayVisible() ? this.searchMessageText.replaceAll('{0}', this.visibleOptions().length) : this.emptySearchMessageText;\n }\n\n get searchMessageText() {\n return this.searchMessage() || this.config.translation.searchMessage || '';\n }\n\n get emptySearchMessageText() {\n return this.emptyMessage() || this.config.translation.emptySearchMessage || '';\n }\n\n get selectionMessageText() {\n return this.selectionMessage() || this.config.translation.selectionMessage || '';\n }\n\n get emptySelectionMessageText() {\n return this.emptySelectionMessage() || this.config.translation.emptySelectionMessage || '';\n }\n\n get selectedMessageText() {\n return this.hasSelectedOption() ? this.selectionMessageText.replaceAll('{0}', this.multiple() ? this.modelValue()?.length : '1') : this.emptySelectionMessageText;\n }\n\n get ariaSetSize() {\n return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;\n }\n\n get listLabel(): string {\n return this.translate(TranslationKeys.ARIA, 'listLabel');\n }\n\n get virtualScrollerDisabled() {\n return !this.virtualScroll();\n }\n\n get optionValueSelected() {\n return typeof this.modelValue() === 'string' && this.optionValue();\n }\n\n chipItemClass(index: number) {\n return this._componentStyle.classes.chipItem({ instance: this, i: index });\n }\n\n constructor() {\n super();\n effect(() => {\n const value = this.suggestions();\n if (value) {\n this.handleSuggestionsChange();\n }\n });\n }\n\n onAfterViewChecked() {\n this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root']));\n //Use timeouts as since Angular 4.2, AfterViewChecked is broken and not called after panel is updated\n if (this.suggestionsUpdated && this.overlayViewChild()) {\n setTimeout(() => {\n if (this.overlayViewChild()) {\n this.overlayViewChild()!.alignOverlay();\n }\n }, 1);\n this.suggestionsUpdated = false;\n }\n }\n\n handleSuggestionsChange() {\n if (this.loading()) {\n this.suggestions()?.length > 0 || this.showEmptyMessage() || !!this.emptyTemplate() ? this.show() : this.hide();\n const focusedOptionIndex = this.overlayVisible() && this.autoOptionFocus() ? this.findFirstFocusedOptionIndex() : -1;\n this.focusedOptionIndex.set(focusedOptionIndex);\n this.suggestionsUpdated = true;\n this.loading.set(false);\n }\n }\n\n flatOptions(options) {\n return (options || []).reduce((result, option, index) => {\n result.push({ optionGroup: option, group: true, index });\n\n const optionGroupChildren = this.getOptionGroupChildren(option);\n\n optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));\n\n return result;\n }, []);\n }\n\n isOptionGroup(option: any): boolean {\n return this.optionGroupLabel() && option.optionGroup && option.group;\n }\n\n findFirstOptionIndex(): number {\n return this.visibleOptions().findIndex((option) => this.isValidOption(option));\n }\n\n findLastOptionIndex(): number {\n return findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));\n }\n\n findFirstFocusedOptionIndex(): number {\n const selectedIndex = this.findSelectedOptionIndex();\n\n return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;\n }\n\n findLastFocusedOptionIndex(): number {\n const selectedIndex = this.findSelectedOptionIndex();\n\n return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;\n }\n\n findSelectedOptionIndex(): number {\n return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;\n }\n\n findNextOptionIndex(index: number): number {\n const matchedOptionIndex =\n index < this.visibleOptions().length - 1\n ? this.visibleOptions()\n .slice(index + 1)\n .findIndex((option) => this.isValidOption(option))\n : -1;\n\n return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;\n }\n\n findPrevOptionIndex(index: number): number {\n const matchedOptionIndex = index > 0 ? findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;\n\n return matchedOptionIndex > -1 ? matchedOptionIndex : index;\n }\n\n isValidSelectedOption(option: any): boolean {\n return this.isValidOption(option) && this.isSelected(option);\n }\n\n isValidOption(option: any): boolean {\n return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));\n }\n\n isOptionDisabled(option: any): boolean {\n return this.optionDisabled() ? resolveFieldData(option, this.optionDisabled()) : false;\n }\n\n isSelected(option: any): boolean {\n if (this.multiple()) {\n return this.unique() ? (this.modelValue() as string[])?.some((model) => equals(model, option, this.equalityKey())) : false;\n }\n return equals(this.modelValue(), option, this.equalityKey());\n }\n\n isOptionMatched(option: any, value: string): boolean {\n return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.searchLocale()) === value.toLocaleLowerCase(this.searchLocale());\n }\n\n isInputClicked(event: MouseEvent): boolean {\n return event.target === this.inputEL()?.nativeElement;\n }\n\n isDropdownClicked(event: MouseEvent): boolean {\n return this.dropdownButton()?.nativeElement ? event.target === this.dropdownButton()!.nativeElement || this.dropdownButton()!.nativeElement.contains(event.target) : false;\n }\n\n equalityKey(): string | undefined {\n return this.optionValue() ? undefined : this.dataKey();\n }\n\n onContainerClick(event: MouseEvent) {\n if (this.$disabled() || this.loading() || this.isInputClicked(event) || this.isDropdownClicked(event)) {\n return;\n }\n\n if (!this.overlayViewChild() || !this.overlayViewChild()!.overlayViewChild()?.nativeElement.contains(event.target)) {\n focus(this.inputEL()?.nativeElement);\n }\n }\n\n handleDropdownClick(event: MouseEvent) {\n let query: string | undefined = undefined;\n\n if (this.overlayVisible()) {\n this.hide(true);\n } else {\n focus(this.inputEL()?.nativeElement);\n query = this.inputEL()?.nativeElement?.value as string;\n\n if (this.dropdownMode() === 'blank') this.search(event, '', 'dropdown');\n else if (this.dropdownMode() === 'current') this.search(event, query, 'dropdown');\n }\n\n this.onDropdownClick.emit({ originalEvent: event, query });\n }\n\n onInput(event: Event) {\n if (this.typeahead()) {\n const _minLength = this.minQueryLength() || 1;\n\n if (this.searchTimeout) {\n clearTimeout(this.searchTimeout);\n }\n\n let query = (event.target as HTMLInputElement).value;\n const maxLen = this.maxlength();\n if (maxLen != null) {\n query = query.split('').slice(0, maxLen).join('');\n }\n\n if (!this.multiple() && !this.forceSelection()) {\n this.updateModel(query);\n }\n\n if (query.length === 0 && !this.multiple()) {\n this.onClear.emit();\n\n setTimeout(() => {\n this.hide();\n }, this.delay() / 2);\n } else {\n if (query.length >= _minLength) {\n