UNPKG

primeng

Version:

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

1 lines 130 kB
{"version":3,"file":"primeng-select.mjs","sources":["../../src/select/style/selectstyle.ts","../../src/select/select.ts","../../src/select/primeng-select.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { style } from '@primeuix/styles/select';\nimport { BaseStyle } from 'primeng/base';\n\nconst theme = /*css*/ `\n ${style}\n\n /* For PrimeNG */\n .p-select-label.p-placeholder {\n color: dt('select.placeholder.color');\n }\n\n .p-select.ng-invalid.ng-dirty {\n border-color: dt('select.invalid.border.color');\n }\n\n .p-dropdown.ng-invalid.ng-dirty .p-dropdown-label.p-placeholder,\n .p-select.ng-invalid.ng-dirty .p-select-label.p-placeholder {\n color: dt('select.invalid.placeholder.color');\n }\n`;\n\nconst classes = {\n root: ({ instance }) => [\n 'p-select p-component p-inputwrapper',\n {\n 'p-disabled': instance.$disabled(),\n 'p-variant-filled': instance.$variant() === 'filled',\n 'p-focus': instance.focused,\n 'p-invalid': instance.invalid(),\n 'p-inputwrapper-filled': instance.$filled(),\n 'p-inputwrapper-focus': instance.focused || instance.overlayVisible,\n 'p-select-open': instance.overlayVisible,\n 'p-select-fluid': instance.hasFluid,\n 'p-select-sm p-inputfield-sm': instance.size() === 'small',\n 'p-select-lg p-inputfield-lg': instance.size() === 'large'\n }\n ],\n label: ({ instance }) => [\n 'p-select-label',\n {\n 'p-placeholder': instance.placeholder() && instance.label() === instance.placeholder(),\n 'p-select-label-empty': !instance.editable && !instance.selectedItemTemplate && (instance.label() === undefined || instance.label() === null || instance.label() === 'p-emptylabel' || instance.label().length === 0)\n }\n ],\n clearIcon: 'p-select-clear-icon',\n dropdown: 'p-select-dropdown',\n loadingIcon: 'p-select-loading-icon',\n dropdownIcon: 'p-select-dropdown-icon',\n overlay: 'p-select-overlay p-component-overlay p-component',\n header: 'p-select-header',\n pcFilter: 'p-select-filter',\n listContainer: 'p-select-list-container',\n list: 'p-select-list',\n optionGroup: 'p-select-option-group',\n optionGroupLabel: 'p-select-option-group-label',\n option: ({ instance }) => [\n 'p-select-option',\n {\n 'p-select-option-selected': instance.selected && !instance.checkmark,\n 'p-disabled': instance.disabled,\n 'p-focus': instance.focused\n }\n ],\n optionLabel: 'p-select-option-label',\n optionCheckIcon: 'p-select-option-check-icon',\n optionBlankIcon: 'p-select-option-blank-icon',\n emptyMessage: 'p-select-empty-message'\n};\n\n@Injectable()\nexport class SelectStyle extends BaseStyle {\n name = 'select';\n\n theme = theme;\n\n classes = classes;\n}\n\n/**\n *\n * Select also known as Select, is used to choose an item from a collection of options.\n *\n * [Live Demo](https://www.primeng.org/select/)\n *\n * @module selectstyle\n *\n */\nexport enum SelectClasses {\n /**\n * Class name of the root element\n */\n root = 'p-select',\n /**\n * Class name of the label element\n */\n label = 'p-select-label',\n /**\n * Class name of the clear icon element\n */\n clearIcon = 'p-select-clear-icon',\n /**\n * Class name of the dropdown element\n */\n dropdown = 'p-select-dropdown',\n /**\n * Class name of the loadingicon element\n */\n loadingIcon = 'p-select-loading-icon',\n /**\n * Class name of the dropdown icon element\n */\n dropdownIcon = 'p-select-dropdown-icon',\n /**\n * Class name of the overlay element\n */\n overlay = 'p-select-overlay',\n /**\n * Class name of the header element\n */\n header = 'p-select-header',\n /**\n * Class name of the filter element\n */\n pcFilter = 'p-select-filter',\n /**\n * Class name of the list container element\n */\n listContainer = 'p-select-list-container',\n /**\n * Class name of the list element\n */\n list = 'p-select-list',\n /**\n * Class name of the option group element\n */\n optionGroup = 'p-select-option-group',\n /**\n * Class name of the option group label element\n */\n optionGroupLabel = 'p-select-option-group-label',\n /**\n * Class name of the option element\n */\n option = 'p-select-option',\n /**\n * Class name of the option label element\n */\n optionLabel = 'p-select-option-label',\n /**\n * Class name of the option check icon element\n */\n optionCheckIcon = 'p-select-option-check-icon',\n /**\n * Class name of the option blank icon element\n */\n optionBlankIcon = 'p-select-option-blank-icon',\n /**\n * Class name of the empty message element\n */\n emptyMessage = 'p-select-empty-message'\n}\n\nexport interface SelectStyle extends BaseStyle {}\n","import { AnimationEvent } from '@angular/animations';\nimport { CommonModule } from '@angular/common';\nimport {\n AfterContentInit,\n AfterViewChecked,\n AfterViewInit,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ContentChild,\n ContentChildren,\n effect,\n ElementRef,\n EventEmitter,\n forwardRef,\n inject,\n input,\n Input,\n NgModule,\n NgZone,\n numberAttribute,\n OnInit,\n Output,\n QueryList,\n Signal,\n signal,\n TemplateRef,\n ViewChild,\n ViewEncapsulation\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { deepEquals, equals, findLastIndex, findSingle, focus, getFirstFocusableElement, getFocusableElements, getLastFocusableElement, isEmpty, isNotEmpty, isPrintableCharacter, resolveFieldData, scrollInView, uuid } from '@primeuix/utils';\nimport { FilterService, OverlayOptions, PrimeTemplate, ScrollerOptions, SharedModule, TranslationKeys } from 'primeng/api';\nimport { AutoFocus } from 'primeng/autofocus';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport { BaseInput } from 'primeng/baseinput';\nimport { unblockBodyScroll } from 'primeng/dom';\nimport { IconField } from 'primeng/iconfield';\nimport { BlankIcon, CheckIcon, ChevronDownIcon, SearchIcon, TimesIcon } from 'primeng/icons';\nimport { InputIcon } from 'primeng/inputicon';\nimport { InputText } from 'primeng/inputtext';\nimport { Overlay } from 'primeng/overlay';\nimport { Ripple } from 'primeng/ripple';\nimport { Scroller } from 'primeng/scroller';\nimport { Tooltip } from 'primeng/tooltip';\nimport { Nullable } from 'primeng/ts-helpers';\nimport { SelectChangeEvent, SelectFilterEvent, SelectFilterOptions, SelectLazyLoadEvent } from './select.interface';\nimport { SelectStyle } from './style/selectstyle';\n\nexport const SELECT_VALUE_ACCESSOR: any = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => Select),\n multi: true\n};\n\n@Component({\n selector: 'p-selectItem',\n standalone: true,\n imports: [CommonModule, SharedModule, Ripple, CheckIcon, BlankIcon],\n template: `\n <li\n [id]=\"id\"\n (click)=\"onOptionClick($event)\"\n (mouseenter)=\"onOptionMouseEnter($event)\"\n role=\"option\"\n pRipple\n [attr.aria-label]=\"label\"\n [attr.aria-setsize]=\"ariaSetSize\"\n [attr.aria-posinset]=\"ariaPosInset\"\n [attr.aria-selected]=\"selected\"\n [attr.data-p-focused]=\"focused\"\n [attr.data-p-highlight]=\"selected\"\n [attr.data-p-disabled]=\"disabled\"\n [ngStyle]=\"{ height: itemSize + 'px' }\"\n [class]=\"cx('option')\"\n >\n <ng-container *ngIf=\"checkmark\">\n <svg data-p-icon=\"check\" *ngIf=\"selected\" [class]=\"cx('optionCheckIcon')\" />\n <svg data-p-icon=\"blank\" *ngIf=\"!selected\" [class]=\"cx('optionBlankIcon')\" />\n </ng-container>\n <span *ngIf=\"!template\">{{ label ?? 'empty' }}</span>\n <ng-container *ngTemplateOutlet=\"template; context: { $implicit: option }\"></ng-container>\n </li>\n `,\n providers: [SelectStyle]\n})\nexport class SelectItem extends BaseComponent {\n @Input() id: string | undefined;\n\n @Input() option: any;\n\n @Input({ transform: booleanAttribute }) selected: boolean | undefined;\n\n @Input({ transform: booleanAttribute }) focused: boolean | undefined;\n\n @Input() label: string | undefined;\n\n @Input({ transform: booleanAttribute }) disabled: boolean | undefined;\n\n @Input({ transform: booleanAttribute }) visible: boolean | undefined;\n\n @Input({ transform: numberAttribute }) itemSize: number | undefined;\n\n @Input() ariaPosInset: string | undefined;\n\n @Input() ariaSetSize: string | undefined;\n\n @Input() template: TemplateRef<any> | undefined;\n\n @Input({ transform: booleanAttribute }) checkmark: boolean;\n\n @Output() onClick: EventEmitter<any> = new EventEmitter();\n\n @Output() onMouseEnter: EventEmitter<any> = new EventEmitter();\n\n _componentStyle = inject(SelectStyle);\n\n onOptionClick(event: Event) {\n this.onClick.emit(event);\n }\n\n onOptionMouseEnter(event: Event) {\n this.onMouseEnter.emit(event);\n }\n}\n\n/**\n * Select is used to choose an item from a collection of options.\n * @group Components\n */\n\n@Component({\n selector: 'p-select',\n standalone: true,\n imports: [CommonModule, SelectItem, Overlay, Tooltip, AutoFocus, TimesIcon, ChevronDownIcon, SearchIcon, InputText, IconField, InputIcon, Scroller, SharedModule],\n template: `\n <span\n #focusInput\n [class]=\"cx('label')\"\n *ngIf=\"!editable\"\n [pTooltip]=\"tooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n [positionStyle]=\"tooltipPositionStyle\"\n [tooltipStyleClass]=\"tooltipStyleClass\"\n [attr.aria-disabled]=\"$disabled()\"\n [attr.id]=\"inputId\"\n role=\"combobox\"\n [attr.aria-label]=\"ariaLabel || (label() === 'p-emptylabel' ? undefined : label())\"\n [attr.aria-labelledby]=\"ariaLabelledBy\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"overlayVisible ?? false\"\n [attr.aria-controls]=\"overlayVisible ? id + '_list' : null\"\n [attr.tabindex]=\"!$disabled() ? tabindex : -1\"\n [pAutoFocus]=\"autofocus\"\n [attr.aria-activedescendant]=\"focused ? focusedOptionId : undefined\"\n (focus)=\"onInputFocus($event)\"\n (blur)=\"onInputBlur($event)\"\n (keydown)=\"onKeyDown($event)\"\n [attr.aria-required]=\"required()\"\n [attr.required]=\"required() ? '' : undefined\"\n [attr.disabled]=\"$disabled() ? '' : undefined\"\n >\n <ng-container *ngIf=\"!selectedItemTemplate && !_selectedItemTemplate; else defaultPlaceholder\">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() }}</ng-container>\n <ng-container *ngIf=\"(selectedItemTemplate || _selectedItemTemplate) && !isSelectedOptionEmpty()\" [ngTemplateOutlet]=\"selectedItemTemplate || _selectedItemTemplate\" [ngTemplateOutletContext]=\"{ $implicit: selectedOption }\"></ng-container>\n <ng-template #defaultPlaceholder>\n <span *ngIf=\"isSelectedOptionEmpty()\">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() }}</span>\n </ng-template>\n </span>\n <input\n *ngIf=\"editable\"\n #editableInput\n type=\"text\"\n [attr.id]=\"inputId\"\n [class]=\"cx('label')\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.placeholder]=\"modelValue() === undefined || modelValue() === null ? placeholder() : undefined\"\n [attr.aria-label]=\"ariaLabel || (label() === 'p-emptylabel' ? undefined : label())\"\n (input)=\"onEditableInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n [pAutoFocus]=\"autofocus\"\n [attr.aria-activedescendant]=\"focused ? focusedOptionId : undefined\"\n (focus)=\"onInputFocus($event)\"\n (blur)=\"onInputBlur($event)\"\n [attr.name]=\"name()\"\n [attr.minlength]=\"minlength()\"\n [attr.min]=\"min()\"\n [attr.max]=\"max()\"\n [attr.pattern]=\"pattern()\"\n [attr.size]=\"inputSize()\"\n [attr.maxlength]=\"maxlength()\"\n [attr.required]=\"required() ? '' : undefined\"\n [attr.readonly]=\"readonly ? '' : undefined\"\n [attr.disabled]=\"$disabled() ? '' : undefined\"\n />\n <ng-container *ngIf=\"isVisibleClearIcon\">\n <svg data-p-icon=\"times\" [class]=\"cx('clearIcon')\" (click)=\"clear($event)\" *ngIf=\"!clearIconTemplate && !_clearIconTemplate\" [attr.data-pc-section]=\"'clearicon'\" />\n <span [class]=\"cx('clearIcon')\" (click)=\"clear($event)\" *ngIf=\"clearIconTemplate || _clearIconTemplate\" [attr.data-pc-section]=\"'clearicon'\">\n <ng-template *ngTemplateOutlet=\"clearIconTemplate || _clearIconTemplate; context: { class: cx('clearIcon') }\"></ng-template>\n </span>\n </ng-container>\n\n <div [class]=\"cx('dropdown')\" role=\"button\" aria-label=\"dropdown trigger\" aria-haspopup=\"listbox\" [attr.aria-expanded]=\"overlayVisible ?? false\" [attr.data-pc-section]=\"'trigger'\">\n <ng-container *ngIf=\"loading; else elseBlock\">\n <ng-container *ngIf=\"loadingIconTemplate || _loadingIconTemplate\">\n <ng-container *ngTemplateOutlet=\"loadingIconTemplate || _loadingIconTemplate\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!loadingIconTemplate && !_loadingIconTemplate\">\n <span *ngIf=\"loadingIcon\" [class]=\"cn(cx('loadingIcon'), 'pi-spin' + loadingIcon)\" aria-hidden=\"true\"></span>\n <span *ngIf=\"!loadingIcon\" [class]=\"cn(cx('loadingIcon'), 'pi pi-spinner pi-spin')\" aria-hidden=\"true\"></span>\n </ng-container>\n </ng-container>\n\n <ng-template #elseBlock>\n <ng-container *ngIf=\"!dropdownIconTemplate && !_dropdownIconTemplate\">\n <span [class]=\"cn(cx('dropdownIcon'), dropdownIcon)\" *ngIf=\"dropdownIcon\"></span>\n <svg data-p-icon=\"chevron-down\" *ngIf=\"!dropdownIcon\" [class]=\"cx('dropdownIcon')\" />\n </ng-container>\n <span *ngIf=\"dropdownIconTemplate || _dropdownIconTemplate\" [class]=\"cx('dropdownIcon')\">\n <ng-template *ngTemplateOutlet=\"dropdownIconTemplate || _dropdownIconTemplate; context: { class: cx('dropdownIcon') }\"></ng-template>\n </span>\n </ng-template>\n </div>\n\n <p-overlay #overlay [hostAttrSelector]=\"attrSelector\" [(visible)]=\"overlayVisible\" [options]=\"overlayOptions\" [target]=\"'@parent'\" [appendTo]=\"$appendTo()\" (onAnimationStart)=\"onOverlayAnimationStart($event)\" (onHide)=\"hide()\">\n <ng-template #content>\n <div [class]=\"cn(cx('overlay'), panelStyleClass)\" [ngStyle]=\"panelStyle\">\n <span\n #firstHiddenFocusableEl\n role=\"presentation\"\n class=\"p-hidden-accessible p-hidden-focusable\"\n [attr.tabindex]=\"0\"\n (focus)=\"onFirstHiddenFocus($event)\"\n [attr.data-p-hidden-accessible]=\"true\"\n [attr.data-p-hidden-focusable]=\"true\"\n >\n </span>\n <ng-container *ngTemplateOutlet=\"headerTemplate || _headerTemplate\"></ng-container>\n <div [class]=\"cx('header')\" *ngIf=\"filter\" (click)=\"$event.stopPropagation()\">\n <ng-container *ngIf=\"filterTemplate || _filterTemplate; else builtInFilterElement\">\n <ng-container *ngTemplateOutlet=\"filterTemplate || _filterTemplate; context: { options: filterOptions }\"></ng-container>\n </ng-container>\n <ng-template #builtInFilterElement>\n <p-iconfield>\n <input\n #filter\n pInputText\n [pSize]=\"size()\"\n type=\"text\"\n role=\"searchbox\"\n autocomplete=\"off\"\n [value]=\"_filterValue() || ''\"\n [class]=\"cx('pcFilter')\"\n [variant]=\"$variant()\"\n [attr.placeholder]=\"filterPlaceholder\"\n [attr.aria-owns]=\"id + '_list'\"\n (input)=\"onFilterInputChange($event)\"\n [attr.aria-label]=\"ariaFilterLabel\"\n [attr.aria-activedescendant]=\"focusedOptionId\"\n (keydown)=\"onFilterKeyDown($event)\"\n (blur)=\"onFilterBlur($event)\"\n />\n <p-inputicon>\n <svg data-p-icon=\"search\" *ngIf=\"!filterIconTemplate && !_filterIconTemplate\" />\n <span *ngIf=\"filterIconTemplate || _filterIconTemplate\">\n <ng-template *ngTemplateOutlet=\"filterIconTemplate || _filterIconTemplate\"></ng-template>\n </span>\n </p-inputicon>\n </p-iconfield>\n </ng-template>\n </div>\n <div [class]=\"cx('listContainer')\" [style.max-height]=\"virtualScroll ? 'auto' : scrollHeight || 'auto'\">\n <p-scroller\n *ngIf=\"virtualScroll\"\n #scroller\n [items]=\"visibleOptions()\"\n [style]=\"{ height: scrollHeight }\"\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; context: { $implicit: items, options: scrollerOptions }\"></ng-container>\n </ng-template>\n <ng-container *ngIf=\"loaderTemplate || _loaderTemplate\">\n <ng-template #loader let-scrollerOptions=\"options\">\n <ng-container *ngTemplateOutlet=\"loaderTemplate || _loaderTemplate; context: { options: scrollerOptions }\"></ng-container>\n </ng-template>\n </ng-container>\n </p-scroller>\n <ng-container *ngIf=\"!virtualScroll\">\n <ng-container *ngTemplateOutlet=\"buildInItems; context: { $implicit: visibleOptions(), options: {} }\"></ng-container>\n </ng-container>\n\n <ng-template #buildInItems let-items let-scrollerOptions=\"options\">\n <ul #items [attr.id]=\"id + '_list'\" [attr.aria-label]=\"listLabel\" [class]=\"cn(cx('list'), scrollerOptions.contentStyleClass)\" [style]=\"scrollerOptions.contentStyle\" role=\"listbox\">\n <ng-template ngFor let-option [ngForOf]=\"items\" let-i=\"index\">\n <ng-container *ngIf=\"isOptionGroup(option)\">\n <li [class]=\"cx('optionGroup')\" [attr.id]=\"id + '_' + getOptionIndex(i, scrollerOptions)\" [ngStyle]=\"{ height: scrollerOptions.itemSize + 'px' }\" role=\"option\">\n <span *ngIf=\"!groupTemplate && !_groupTemplate\">{{ getOptionGroupLabel(option.optionGroup) }}</span>\n <ng-container *ngTemplateOutlet=\"groupTemplate || _groupTemplate; context: { $implicit: option.optionGroup }\"></ng-container>\n </li>\n </ng-container>\n <ng-container *ngIf=\"!isOptionGroup(option)\">\n <p-selectItem\n [id]=\"id + '_' + getOptionIndex(i, scrollerOptions)\"\n [option]=\"option\"\n [checkmark]=\"checkmark\"\n [selected]=\"isSelected(option)\"\n [label]=\"getOptionLabel(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n [template]=\"itemTemplate || _itemTemplate\"\n [focused]=\"focusedOptionIndex() === getOptionIndex(i, scrollerOptions)\"\n [ariaPosInset]=\"getAriaPosInset(getOptionIndex(i, scrollerOptions))\"\n [ariaSetSize]=\"ariaSetSize\"\n (onClick)=\"onOptionSelect($event, option)\"\n (onMouseEnter)=\"onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))\"\n ></p-selectItem>\n </ng-container>\n </ng-template>\n <li *ngIf=\"filterValue && isEmpty()\" [class]=\"cx('emptyMessage')\" [ngStyle]=\"{ height: scrollerOptions.itemSize + 'px' }\" role=\"option\">\n @if (!emptyFilterTemplate && !_emptyFilterTemplate && !emptyTemplate) {\n {{ emptyFilterMessageLabel }}\n } @else {\n <ng-container #emptyFilter *ngTemplateOutlet=\"emptyFilterTemplate || _emptyFilterTemplate || emptyTemplate || _emptyTemplate\"></ng-container>\n }\n </li>\n <li *ngIf=\"!filterValue && isEmpty()\" [class]=\"cx('emptyMessage')\" [ngStyle]=\"{ height: scrollerOptions.itemSize + 'px' }\" role=\"option\">\n @if (!emptyTemplate && !_emptyTemplate) {\n {{ emptyMessageLabel }}\n } @else {\n <ng-container #empty *ngTemplateOutlet=\"emptyTemplate || _emptyTemplate\"></ng-container>\n }\n </li>\n </ul>\n </ng-template>\n </div>\n <ng-container *ngTemplateOutlet=\"footerTemplate || _footerTemplate\"></ng-container>\n <span\n #lastHiddenFocusableEl\n role=\"presentation\"\n class=\"p-hidden-accessible p-hidden-focusable\"\n [attr.tabindex]=\"0\"\n (focus)=\"onLastHiddenFocus($event)\"\n [attr.data-p-hidden-accessible]=\"true\"\n [attr.data-p-hidden-focusable]=\"true\"\n ></span>\n </div>\n </ng-template>\n </p-overlay>\n `,\n host: {\n '[class]': \"cn(cx('root'), styleClass)\",\n '[attr.id]': 'id',\n '(click)': 'onContainerClick($event)'\n },\n providers: [SELECT_VALUE_ACCESSOR, SelectStyle],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None\n})\nexport class Select extends BaseInput implements OnInit, AfterViewInit, AfterContentInit, AfterViewChecked {\n /**\n * Unique identifier of the component\n * @group Props\n */\n @Input() id: string | undefined;\n /**\n * Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value.\n * @group Props\n */\n @Input() scrollHeight: string = '200px';\n /**\n * When specified, displays an input field to filter the items on keyup.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) filter: boolean | undefined;\n /**\n * Inline style of the overlay panel element.\n * @group Props\n */\n @Input() panelStyle: { [klass: string]: any } | null | undefined;\n /**\n * Style class of the element.\n * @deprecated since v20.0.0, use `class` instead.\n * @group Props\n */\n @Input() styleClass: string | undefined;\n /**\n * Style class of the overlay panel element.\n * @group Props\n */\n @Input() panelStyleClass: string | undefined;\n /**\n * When present, it specifies that the component cannot be edited.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) readonly: boolean | undefined;\n /**\n * When present, custom value instead of predefined options can be entered using the editable input field.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) editable: boolean | undefined;\n /**\n * Index of the element in tabbing order.\n * @group Props\n */\n @Input({ transform: numberAttribute }) tabindex: number | undefined = 0;\n /**\n * Default text to display when no option is selected.\n * @group Props\n */\n @Input() set placeholder(val: string | undefined) {\n this._placeholder.set(val);\n }\n get placeholder(): Signal<string | undefined> {\n return this._placeholder.asReadonly();\n }\n /**\n * Icon to display in loading state.\n * @group Props\n */\n @Input() loadingIcon: string | undefined;\n /**\n * Placeholder text to show when filter input is empty.\n * @group Props\n */\n @Input() filterPlaceholder: string | undefined;\n /**\n * Locale to use in filtering. The default locale is the host environment's current locale.\n * @group Props\n */\n @Input() filterLocale: string | undefined;\n /**\n * Identifier of the accessible input element.\n * @group Props\n */\n @Input() inputId: string | undefined;\n /**\n * A property to uniquely identify a value in options.\n * @group Props\n */\n @Input() dataKey: string | undefined;\n /**\n * When filtering is enabled, filterBy decides which field or fields (comma separated) to search against.\n * @group Props\n */\n @Input() filterBy: string | undefined;\n /**\n * Fields used when filtering the options, defaults to optionLabel.\n * @group Props\n */\n @Input() filterFields: any[] | undefined;\n /**\n * When present, it specifies that the component should automatically get focus on load.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) autofocus: boolean | undefined;\n /**\n * Clears the filter value when hiding the select.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) resetFilterOnHide: boolean = false;\n /**\n * Whether the selected option will be shown with a check mark.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) checkmark: boolean = false;\n /**\n * Icon class of the select icon.\n * @group Props\n */\n @Input() dropdownIcon: string | undefined;\n /**\n * Whether the select is in loading state.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) loading: boolean | undefined = false;\n /**\n * Name of the label field of an option.\n * @group Props\n */\n @Input() optionLabel: string | undefined;\n /**\n * Name of the value field of an option.\n * @group Props\n */\n @Input() optionValue: string | undefined;\n /**\n * Name of the disabled field of an option.\n * @group Props\n */\n @Input() optionDisabled: string | undefined;\n /**\n * Name of the label field of an option group.\n * @group Props\n */\n @Input() optionGroupLabel: string | undefined = 'label';\n /**\n * Name of the options field of an option group.\n * @group Props\n */\n @Input() optionGroupChildren: string = 'items';\n /**\n * Whether to display options as grouped when nested options are provided.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) group: boolean | undefined;\n /**\n * When enabled, a clear icon is displayed to clear the value.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) showClear: boolean | undefined;\n /**\n * Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.\n * @group Props\n */\n @Input() emptyFilterMessage: string = '';\n /**\n * Text to display when there is no data. Defaults to global value in i18n translation configuration.\n * @group Props\n */\n @Input() emptyMessage: string = '';\n /**\n * Defines if data is loaded and interacted with in lazy manner.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) lazy: boolean = false;\n /**\n * Whether the data should be loaded on demand during scroll.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) virtualScroll: boolean | undefined;\n /**\n * Height of an item in the list for VirtualScrolling.\n * @group Props\n */\n @Input({ transform: numberAttribute }) virtualScrollItemSize: number | undefined;\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 @Input() virtualScrollOptions: ScrollerOptions | undefined;\n /**\n * Whether to use overlay API feature. The properties of overlay API can be used like an object in it.\n * @group Props\n */\n @Input() overlayOptions: OverlayOptions | undefined;\n /**\n * Defines a string that labels the filter input.\n * @group Props\n */\n @Input() ariaFilterLabel: string | undefined;\n /**\n * Used to define a aria label attribute the current element.\n * @group Props\n */\n @Input() ariaLabel: string | undefined;\n /**\n * Establishes relationships between the component and label(s) where its value should be one or more element IDs.\n * @group Props\n */\n @Input() ariaLabelledBy: string | undefined;\n /**\n * Defines how the items are filtered.\n * @group Props\n */\n @Input() filterMatchMode: 'contains' | 'startsWith' | 'endsWith' | 'equals' | 'notEquals' | 'in' | 'lt' | 'lte' | 'gt' | 'gte' = 'contains';\n /**\n * Advisory information to display in a tooltip on hover.\n * @group Props\n */\n @Input() tooltip: string = '';\n /**\n * Position of the tooltip.\n * @group Props\n */\n @Input() tooltipPosition: 'top' | 'left' | 'right' | 'bottom' = 'right';\n /**\n * Type of CSS position.\n * @group Props\n */\n @Input() tooltipPositionStyle: string = 'absolute';\n /**\n * Style class of the tooltip.\n * @group Props\n */\n @Input() tooltipStyleClass: string | undefined;\n /**\n * Fields used when filtering the options, defaults to optionLabel.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) focusOnHover: boolean = true;\n /**\n * Determines if the option will be selected on focus.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) selectOnFocus: boolean = false;\n /**\n * Whether to focus on the first visible or selected element when the overlay panel is shown.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) autoOptionFocus: boolean = false;\n /**\n * Applies focus to the filter element when the overlay is shown.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) autofocusFilter: boolean = true;\n /**\n * When specified, filter displays with this value.\n * @group Props\n */\n @Input() get filterValue(): string | undefined | null {\n return this._filterValue();\n }\n set filterValue(val: string | undefined | null) {\n setTimeout(() => {\n this._filterValue.set(val);\n });\n }\n /**\n * An array of objects to display as the available options.\n * @group Props\n */\n @Input() get options(): any[] | undefined {\n const options = this._options();\n return options;\n }\n set options(val: any[] | undefined) {\n if (!deepEquals(val, this._options())) {\n this._options.set(val);\n }\n }\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<HTMLElement | ElementRef | TemplateRef<any> | 'self' | 'body' | null | undefined | any>(undefined);\n /**\n * Callback to invoke when value of select changes.\n * @param {SelectChangeEvent} event - custom change event.\n * @group Emits\n */\n @Output() onChange: EventEmitter<SelectChangeEvent> = new EventEmitter<SelectChangeEvent>();\n /**\n * Callback to invoke when data is filtered.\n * @param {SelectFilterEvent} event - custom filter event.\n * @group Emits\n */\n @Output() onFilter: EventEmitter<SelectFilterEvent> = new EventEmitter<SelectFilterEvent>();\n /**\n * Callback to invoke when select gets focus.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n @Output() onFocus: EventEmitter<Event> = new EventEmitter<Event>();\n /**\n * Callback to invoke when select loses focus.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n @Output() onBlur: EventEmitter<Event> = new EventEmitter<Event>();\n /**\n * Callback to invoke when component is clicked.\n * @param {MouseEvent} event - Mouse event.\n * @group Emits\n */\n @Output() onClick: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();\n /**\n * Callback to invoke when select overlay gets visible.\n * @param {AnimationEvent} event - Animation event.\n * @group Emits\n */\n @Output() onShow: EventEmitter<AnimationEvent> = new EventEmitter<AnimationEvent>();\n /**\n * Callback to invoke when select overlay gets hidden.\n * @param {AnimationEvent} event - Animation event.\n * @group Emits\n */\n @Output() onHide: EventEmitter<AnimationEvent> = new EventEmitter<AnimationEvent>();\n /**\n * Callback to invoke when select clears the value.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n @Output() onClear: EventEmitter<Event> = new EventEmitter<Event>();\n /**\n * Callback to invoke in lazy mode to load new data.\n * @param {SelectLazyLoadEvent} event - Lazy load event.\n * @group Emits\n */\n @Output() onLazyLoad: EventEmitter<SelectLazyLoadEvent> = new EventEmitter<SelectLazyLoadEvent>();\n\n _componentStyle = inject(SelectStyle);\n\n @ViewChild('filter') filterViewChild: Nullable<ElementRef>;\n\n @ViewChild('focusInput') focusInputViewChild: Nullable<ElementRef>;\n\n @ViewChild('editableInput') editableInputViewChild: Nullable<ElementRef>;\n\n @ViewChild('items') itemsViewChild: Nullable<ElementRef>;\n\n @ViewChild('scroller') scroller: Nullable<Scroller>;\n\n @ViewChild('overlay') overlayViewChild: Nullable<Overlay>;\n\n @ViewChild('firstHiddenFocusableEl') firstHiddenFocusableElementOnOverlay: Nullable<ElementRef>;\n\n @ViewChild('lastHiddenFocusableEl') lastHiddenFocusableElementOnOverlay: Nullable<ElementRef>;\n\n itemsWrapper: Nullable<HTMLDivElement>;\n\n $appendTo = computed(() => this.appendTo() || this.config.overlayAppendTo());\n\n /**\n * Custom item template.\n * @group Templates\n */\n @ContentChild('item', { descendants: false }) itemTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom group template.\n * @group Templates\n */\n @ContentChild('group', { descendants: false }) groupTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom loader template.\n * @group Templates\n */\n @ContentChild('loader', { descendants: false }) loaderTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom selected item template.\n * @group Templates\n */\n @ContentChild('selectedItem', { descendants: false }) selectedItemTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom header template.\n * @group Templates\n */\n @ContentChild('header', { descendants: false }) headerTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom filter template.\n * @group Templates\n */\n @ContentChild('filter', { descendants: false }) filterTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom footer template.\n * @group Templates\n */\n @ContentChild('footer', { descendants: false }) footerTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom empty filter template.\n * @group Templates\n */\n @ContentChild('emptyfilter', { descendants: false }) emptyFilterTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom empty template.\n * @group Templates\n */\n @ContentChild('empty', { descendants: false }) emptyTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom dropdown icon template.\n * @group Templates\n */\n @ContentChild('dropdownicon', { descendants: false }) dropdownIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom loading icon template.\n * @group Templates\n */\n @ContentChild('loadingicon', { descendants: false }) loadingIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom clear icon template.\n * @group Templates\n */\n @ContentChild('clearicon', { descendants: false }) clearIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom filter icon template.\n * @group Templates\n */\n @ContentChild('filtericon', { descendants: false }) filterIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom on icon template.\n * @group Templates\n */\n @ContentChild('onicon', { descendants: false }) onIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom off icon template.\n * @group Templates\n */\n @ContentChild('officon', { descendants: false }) offIconTemplate: Nullable<TemplateRef<any>>;\n\n /**\n * Custom cancel icon template.\n * @group Templates\n */\n @ContentChild('cancelicon', { descendants: false }) cancelIconTemplate: Nullable<TemplateRef<any>>;\n\n @ContentChildren(PrimeTemplate) templates: QueryList<PrimeTemplate> | undefined;\n\n _itemTemplate: TemplateRef<any> | undefined;\n\n _selectedItemTemplate: TemplateRef<any> | undefined;\n\n _headerTemplate: TemplateRef<any> | undefined;\n\n _filterTemplate: TemplateRef<any> | undefined;\n\n _footerTemplate: TemplateRef<any> | undefined;\n\n _emptyFilterTemplate: TemplateRef<any> | undefined;\n\n _emptyTemplate: TemplateRef<any> | undefined;\n\n _groupTemplate: TemplateRef<any> | undefined;\n\n _loaderTemplate: TemplateRef<any> | undefined;\n\n _dropdownIconTemplate: TemplateRef<any> | undefined;\n\n _loadingIconTemplate: TemplateRef<any> | undefined;\n\n _clearIconTemplate: TemplateRef<any> | undefined;\n\n _filterIconTemplate: TemplateRef<any> | undefined;\n\n _cancelIconTemplate: TemplateRef<any> | undefined;\n\n _onIconTemplate: TemplateRef<any> | undefined;\n\n _offIconTemplate: TemplateRef<any> | undefined;\n\n filterOptions: SelectFilterOptions | undefined;\n\n _options = signal<any[] | undefined>(null);\n\n _placeholder = signal<string | undefined>(undefined);\n\n value: any;\n\n hover: Nullable<boolean>;\n\n focused: Nullable<boolean>;\n\n overlayVisible: Nullable<boolean>;\n\n optionsChanged: Nullable<boolean>;\n\n panel: Nullable<HTMLDivElement>;\n\n dimensionsUpdated: Nullable<boolean>;\n\n hoveredItem: any;\n\n selectedOptionUpdated: Nullable<boolean>;\n\n _filterValue = signal<any>(null);\n\n searchValue: Nullable<string>;\n\n searchIndex: Nullable<number>;\n\n searchTimeout: any;\n\n previousSearchChar: Nullable<string>;\n\n currentSearchChar: Nullable<string>;\n\n preventModelTouched: Nullable<boolean>;\n\n focusedOptionIndex = signal<number>(-1);\n\n labelId: Nullable<string>;\n\n listId: Nullable<string>;\n\n clicked = signal<boolean>(false);\n\n get emptyMessageLabel(): string {\n return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);\n }\n\n get emptyFilterMessageLabel(): string {\n return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);\n }\n\n get isVisibleClearIcon(): boolean | undefined {\n return this.modelValue() != null && this.hasSelectedOption() && this.showClear && !this.$disabled();\n }\n\n get listLabel(): string {\n return this.config.getTranslation(TranslationKeys.ARIA)['listLabel'];\n }\n\n get focusedOptionId() {\n return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;\n }\n\n visibleOptions = computed(() => {\n const options = this.getAllVisibleAndNonVisibleOptions();\n\n if (this._filterValue()) {\n const _filterBy = this.filterBy || this.optionLabel;\n\n const filteredOptions =\n !_filterBy && !this.filterFields && !this.optionValue\n ? this.options.filter((option) => {\n if (option.label) {\n return option.label.toString().toLowerCase().indexOf(this._filterValue().toLowerCase().trim()) !== -1;\n }\n return option.toString().toLowerCase().indexOf(this._filterValue().toLowerCase().trim()) !== -1;\n })\n : this.filterService.filter(options, this.searchFields(), this._filterValue().trim(), this.filterMatchMode, this.filterLocale);\n\n if (this.group) {\n const optionGroups = this.options || [];\n const filtered = [];\n\n optionGroups.forEach((group) => {\n const groupChildren = this.getOptionGroupChildren(group);\n const filteredItems = groupChildren.filter((item) => filteredOptions.includes(item));\n\n if (filteredItems.length > 0)\n filtered.push({\n ...group,\n [typeof this.optionGroupChildren === 'string' ? this.optionGroupChildren : 'items']: [...filteredItems]\n });\n });\n\n return this.flatOptions(filtered);\n }\n return filteredOptions;\n }\n\n return options;\n });\n\n label = computed(() => {\n // use getAllVisibleAndNonVisibleOptions verses just visible options\n // this will find the selected option whether or not the user is currently filtering because the filtered (i.e. visible) options, are a subset of all the options\n const options = this.getAllVisibleAndNonVisibleOptions();\n // use isOptionEqualsModelValue for the use case where the dropdown is initalized with a disabled option\n const selectedOptionIndex = options.findIndex((option) => this.isOptionValueEqualsModelValue(option));\n\n return selectedOptionIndex !== -1 ? this.getOptionLabel(options[selectedOptionIndex]) : this.placeholder() || 'p-emptylabel';\n });\n\n selectedOption: any;\n\n constructor(\n public zone: NgZone,\n public filterService: FilterService\n ) {\n super();\n effect(() => {\n const modelValue = this.modelValue();\n const visibleOptions = this.visibleOptions();\n\n if (visibleOptions && isNotEmpty(visibleOptions)) {\n const selectedOptionIndex = this.findSelectedOptionIndex();\n\n if (selectedOptionIndex !== -1 || modelValue === undefined || (typeof modelValue === 'string' && modelValue.length === 0) || this.isModelValueNotSet() || this.editable) {\n this.selectedOption = visibleOptions[selectedOptionIndex];\n }\n }\n\n if (isEmpty(visibleOptions) && (modelValue === undefined || this.isModelValueNotSet()) && isNotEmpty(this.selectedOption)) {\n this.selectedOption = null;\n }\n\n if (modelValue !== undefined && this.editable) {\n this.updateEditableLabel();\n }\n this.cd.markForCheck();\n });\n }\n\n private isModelValueNotSet(): boolean {\n return this.modelValue() === null && !this.isOptionValueEqualsModelValue(this.selectedOption);\n }\n\n private getAllVisibleAndNonVisibleOptions() {\n return this.group ? this.flatOptions(this.options) : this.options || [];\n }\n\n ngOnInit() {\n super.ngOnInit();\n this.id = this.id || uuid('pn_id_');\n this.autoUpdateModel();\n\n if (this.filterBy) {\n this.filterOptions = {\n filter: (value) => this.onFilterInputChange(value),\n reset: () => this.resetFilter()\n };\n }\n }\n\n ngAfterContentInit() {\n (this.templates as QueryList<PrimeTemplate>).forEach((item) => {\n switch (item.getType()) {\n case 'item':\n this._itemTemplate = item.template;\n break;\n\n case 'selectedItem':\n this._selectedItemTemplate = item.template;\n break;\n\n case 'header':\n this._headerTemplate = item.template;\n break;\n\n case 'filter':\n this._filterTemplate = item.template;\n break;\n\n case 'footer':\n this._footerTemplate = item.template;\n break;\n\n case 'emptyfilter':\n this._emptyFilterTemplate = item.template;\n break;\n\n case 'empty':\n this._emptyTemplate = item.template;\n break;\n\n case 'group':\n this._groupTemplate = item.template;\n break;\n\n case 'loader':\n this._loaderTemplate = item.template;\n break;\n\n case 'dropdownicon':\n this._dropdownIconTemplate = item.template;\n break;\n\n case 'loadingicon':\n this._loadingIconTemplate = item.template;\n break;\n\n case 'clearicon':\n this._clearIconTemplate = item.template;\n break;\n\n case 'filtericon':\n this._filterIconTemplate = item.template;\n break;\n\n case 'cancelicon':\n this._cancelIconTemplate = item.template;\n break;\n\n case 'onicon':\n this._onIconTemplate = item.template;\n break;\n\n case 'officon':\n this._offIconTemplate = item.template;\n break;\n\n default:\n this._itemTemplate = item.template;\n break;\n }\n });\n }\n\n ngAfterViewChecked() {\n if (this.optionsChanged && this.overlayVisible) {\n this.optionsChanged = false;\n\n this.zone.runOutsideAngular(() => {\n setTimeout(() => {\n if (this.overlayViewChild) {\n this.overlayViewChild.alignOverlay();\n }\n }, 1);\n });\n