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,000 lines (996 loc) • 134 kB
JavaScript
export * from 'primeng/types/select';
import { NgTemplateOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, inject, input, booleanAttribute, numberAttribute, computed, output, Component, forwardRef, viewChild, contentChild, signal, effect, ViewEncapsulation, ChangeDetectionStrategy, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ChevronDown } from '@primeicons/angular/chevron-down';
import { Search } from '@primeicons/angular/search';
import { Times } from '@primeicons/angular/times';
import { uuid, equals, isNotEmpty, isEmpty, deepEquals, findSingle, scrollInView, resolveFieldData, focus, isPrintableCharacter, findLastIndex, getFirstFocusableElement, getLastFocusableElement, getFocusableElements } from '@primeuix/utils';
import { SharedModule, FilterService, TranslationKeys } from 'primeng/api';
import { AutoFocus } from 'primeng/autofocus';
import { BaseComponent, PARENT_INSTANCE } from 'primeng/basecomponent';
import { BaseInput } from 'primeng/baseinput';
import * as i1 from 'primeng/bind';
import { BindModule, Bind } from 'primeng/bind';
import { unblockBodyScroll } from 'primeng/dom';
import { IconField } from 'primeng/iconfield';
import { InputIcon } from 'primeng/inputicon';
import { InputText } from 'primeng/inputtext';
import { Overlay } from 'primeng/overlay';
import { Scroller } from 'primeng/scroller';
import { Tooltip } from 'primeng/tooltip';
import { Check } from '@primeicons/angular/check';
import { Blank } from '@primeicons/angular/blank';
import { Ripple } from 'primeng/ripple';
import { style } from '@primeuix/styles/select';
import { BaseStyle } from 'primeng/base';
const SELECT_INSTANCE = new InjectionToken('SELECT_INSTANCE');
const SELECT_ITEM_INSTANCE = new InjectionToken('SELECT_ITEM_INSTANCE');
const classes = {
root: ({ instance }) => [
'p-select p-component p-inputwrapper',
{
'p-disabled': instance.$disabled(),
'p-invalid': instance.invalid(),
'p-variant-filled': instance.$variant() === 'filled',
'p-focus': instance.focused(),
'p-inputwrapper-filled': instance.$filled(),
'p-inputwrapper-focus': instance.focused() || instance.overlayVisible(),
'p-select-open': instance.overlayVisible(),
'p-select-fluid': instance.hasFluid,
'p-select-sm p-inputfield-sm': instance.size() === 'small',
'p-select-lg p-inputfield-lg': instance.size() === 'large'
}
],
label: ({ instance }) => [
'p-select-label',
{
'p-placeholder': instance.placeholder() && instance.label() === instance.placeholder(),
'p-select-label-empty': !instance.editable() && !instance.selectedItemTemplate() && (instance.label() === undefined || instance.label() === null || instance.label() === 'p-emptylabel' || instance.label().length === 0)
}
],
clearIcon: 'p-select-clear-icon',
dropdown: 'p-select-dropdown',
loadingIcon: 'p-select-loading-icon',
dropdownIcon: 'p-select-dropdown-icon',
overlay: 'p-select-overlay p-component-overlay p-component',
header: 'p-select-header',
pcFilter: 'p-select-filter',
listContainer: 'p-select-list-container',
list: 'p-select-list',
optionGroup: 'p-select-option-group',
optionGroupLabel: 'p-select-option-group-label',
option: ({ instance }) => [
'p-select-option',
{
'p-select-option-selected': instance.selected() && !instance.checkmark(),
'p-disabled': instance.disabled(),
'p-focus': instance.focused()
}
],
optionLabel: 'p-select-option-label',
optionCheckIcon: 'p-select-option-check-icon',
optionBlankIcon: 'p-select-option-blank-icon',
emptyMessage: 'p-select-empty-message'
};
class SelectStyle extends BaseStyle {
name = 'select';
style = style;
classes = classes;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SelectStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SelectStyle });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SelectStyle, decorators: [{
type: Injectable
}] });
/**
*
* Select also known as Select, is used to choose an item from a collection of options.
*
* [Live Demo](https://www.primeng.org/select/)
*
* @module selectstyle
*
*/
var SelectClasses;
(function (SelectClasses) {
/**
* Class name of the root element
*/
SelectClasses["root"] = "p-select";
/**
* Class name of the label element
*/
SelectClasses["label"] = "p-select-label";
/**
* Class name of the clear icon element
*/
SelectClasses["clearIcon"] = "p-select-clear-icon";
/**
* Class name of the dropdown element
*/
SelectClasses["dropdown"] = "p-select-dropdown";
/**
* Class name of the loadingicon element
*/
SelectClasses["loadingIcon"] = "p-select-loading-icon";
/**
* Class name of the dropdown icon element
*/
SelectClasses["dropdownIcon"] = "p-select-dropdown-icon";
/**
* Class name of the overlay element
*/
SelectClasses["overlay"] = "p-select-overlay";
/**
* Class name of the header element
*/
SelectClasses["header"] = "p-select-header";
/**
* Class name of the filter element
*/
SelectClasses["pcFilter"] = "p-select-filter";
/**
* Class name of the list container element
*/
SelectClasses["listContainer"] = "p-select-list-container";
/**
* Class name of the list element
*/
SelectClasses["list"] = "p-select-list";
/**
* Class name of the option group element
*/
SelectClasses["optionGroup"] = "p-select-option-group";
/**
* Class name of the option group label element
*/
SelectClasses["optionGroupLabel"] = "p-select-option-group-label";
/**
* Class name of the option element
*/
SelectClasses["option"] = "p-select-option";
/**
* Class name of the option label element
*/
SelectClasses["optionLabel"] = "p-select-option-label";
/**
* Class name of the option check icon element
*/
SelectClasses["optionCheckIcon"] = "p-select-option-check-icon";
/**
* Class name of the option blank icon element
*/
SelectClasses["optionBlankIcon"] = "p-select-option-blank-icon";
/**
* Class name of the empty message element
*/
SelectClasses["emptyMessage"] = "p-select-empty-message";
})(SelectClasses || (SelectClasses = {}));
class SelectItem extends BaseComponent {
hostName = 'select';
$pcSelectItem = inject(SELECT_ITEM_INSTANCE, { optional: true, skipSelf: true }) ?? undefined;
$pcSelect = inject(SELECT_INSTANCE, { optional: true, skipSelf: true });
id = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
option = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "option" }] : /* istanbul ignore next */ []));
selected = input(undefined, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
focused = input(undefined, { ...(ngDevMode ? { debugName: "focused" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
label = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
disabled = input(undefined, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
visible = input(undefined, { ...(ngDevMode ? { debugName: "visible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
itemSize = input(undefined, { ...(ngDevMode ? { debugName: "itemSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
ariaPosInset = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaPosInset" }] : /* istanbul ignore next */ []));
ariaSetSize = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaSetSize" }] : /* istanbul ignore next */ []));
template = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "template" }] : /* istanbul ignore next */ []));
checkmark = input(false, { ...(ngDevMode ? { debugName: "checkmark" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
index = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "index" }] : /* istanbul ignore next */ []));
scrollerOptions = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "scrollerOptions" }] : /* istanbul ignore next */ []));
templateContext = computed(() => ({ $implicit: this.option() }), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "templateContext" }] : /* istanbul ignore next */ []));
itemSizeStyle = computed(() => ({ height: this.scrollerOptions()?.itemSize + 'px' }), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "itemSizeStyle" }] : /* istanbul ignore next */ []));
onClick = output();
onMouseEnter = output();
_componentStyle = inject(SelectStyle);
onOptionClick(event) {
this.onClick.emit(event);
}
onOptionMouseEnter(event) {
this.onMouseEnter.emit(event);
}
getPTOptions() {
return (this.$pcSelect?.getPTItemOptions?.(this.option(), this.scrollerOptions(), this.index() ?? 0, 'option') ??
this.$pcSelect?.ptm('option', {
context: {
option: this.option(),
selected: this.selected(),
focused: this.focused(),
disabled: this.disabled()
}
}));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SelectItem, deps: null, target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: SelectItem, isStandalone: true, selector: "p-select-item", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, option: { classPropertyName: "option", publicName: "option", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, focused: { classPropertyName: "focused", publicName: "focused", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, ariaPosInset: { classPropertyName: "ariaPosInset", publicName: "ariaPosInset", isSignal: true, isRequired: false, transformFunction: null }, ariaSetSize: { classPropertyName: "ariaSetSize", publicName: "ariaSetSize", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: false, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: false, transformFunction: null }, scrollerOptions: { classPropertyName: "scrollerOptions", publicName: "scrollerOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick", onMouseEnter: "onMouseEnter" }, providers: [SelectStyle, { provide: PARENT_INSTANCE, useExisting: SelectItem }], usesInheritance: true, ngImport: i0, template: `
<li
[id]="id()"
[pBind]="getPTOptions()"
(click)="onOptionClick($event)"
(mouseenter)="onOptionMouseEnter($event)"
role="option"
pRipple
[attr.aria-label]="label()"
[attr.aria-setsize]="ariaSetSize()"
[attr.aria-posinset]="ariaPosInset()"
[attr.aria-selected]="selected()"
[attr.data-p-focused]="focused()"
[attr.data-p-highlight]="selected()"
[attr.data-p-selected]="selected()"
[attr.data-p-disabled]="disabled()"
[style]="itemSizeStyle()"
[class]="cx('option')"
>
@if (checkmark()) {
@if (selected()) {
<svg data-p-icon="check" [class]="cx('optionCheckIcon')" [pBind]="$pcSelect?.ptm('optionCheckIcon')" />
} @else {
<svg data-p-icon="blank" [class]="cx('optionBlankIcon')" [pBind]="$pcSelect?.ptm('optionBlankIcon')" />
}
}
@if (!template()) {
<span [pBind]="$pcSelect?.ptm('optionLabel')">{{ label() ?? 'empty' }}</span>
}
<ng-container *ngTemplateOutlet="template(); context: templateContext()"></ng-container>
</li>
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SharedModule }, { kind: "directive", type: Ripple, selector: "[pRipple]" }, { kind: "component", type: Check, selector: "svg[data-p-icon=\"check\"]" }, { kind: "component", type: Blank, selector: "svg[data-p-icon=\"blank\"]" }, { kind: "ngmodule", type: BindModule }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SelectItem, decorators: [{
type: Component,
args: [{
selector: 'p-select-item',
standalone: true,
imports: [NgTemplateOutlet, SharedModule, Ripple, Check, Blank, BindModule],
template: `
<li
[id]="id()"
[pBind]="getPTOptions()"
(click)="onOptionClick($event)"
(mouseenter)="onOptionMouseEnter($event)"
role="option"
pRipple
[attr.aria-label]="label()"
[attr.aria-setsize]="ariaSetSize()"
[attr.aria-posinset]="ariaPosInset()"
[attr.aria-selected]="selected()"
[attr.data-p-focused]="focused()"
[attr.data-p-highlight]="selected()"
[attr.data-p-selected]="selected()"
[attr.data-p-disabled]="disabled()"
[style]="itemSizeStyle()"
[class]="cx('option')"
>
@if (checkmark()) {
@if (selected()) {
<svg data-p-icon="check" [class]="cx('optionCheckIcon')" [pBind]="$pcSelect?.ptm('optionCheckIcon')" />
} @else {
<svg data-p-icon="blank" [class]="cx('optionBlankIcon')" [pBind]="$pcSelect?.ptm('optionBlankIcon')" />
}
}
@if (!template()) {
<span [pBind]="$pcSelect?.ptm('optionLabel')">{{ label() ?? 'empty' }}</span>
}
<ng-container *ngTemplateOutlet="template(); context: templateContext()"></ng-container>
</li>
`,
providers: [SelectStyle, { provide: PARENT_INSTANCE, useExisting: SelectItem }]
}]
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], option: [{ type: i0.Input, args: [{ isSignal: true, alias: "option", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], focused: [{ type: i0.Input, args: [{ isSignal: true, alias: "focused", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], itemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemSize", required: false }] }], ariaPosInset: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaPosInset", required: false }] }], ariaSetSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaSetSize", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }], checkmark: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkmark", required: false }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: false }] }], scrollerOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollerOptions", required: false }] }], onClick: [{ type: i0.Output, args: ["onClick"] }], onMouseEnter: [{ type: i0.Output, args: ["onMouseEnter"] }] } });
const SELECT_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Select),
multi: true
};
/**
* Select is used to choose an item from a collection of options.
* @group Components
*/
class Select extends BaseInput {
componentName = 'Select';
bindDirectiveInstance = inject(Bind, { self: true });
filterService = inject(FilterService);
/**
* Unique identifier of the component
* @group Props
*/
id = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
_internalId = uuid('pn_id_');
$id = computed(() => this.id() || this._internalId, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$id" }] : /* istanbul ignore next */ []));
/**
* Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value.
* @group Props
*/
scrollHeight = input('200px', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "scrollHeight" }] : /* istanbul ignore next */ []));
/**
* When specified, displays an input field to filter the items on keyup.
* @group Props
*/
filter = input(undefined, { ...(ngDevMode ? { debugName: "filter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Inline style of the overlay panel element.
* @group Props
*/
panelStyle = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "panelStyle" }] : /* istanbul ignore next */ []));
/**
* Style class of the overlay panel element.
* @group Props
*/
panelStyleClass = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "panelStyleClass" }] : /* istanbul ignore next */ []));
/**
* When present, it specifies that the component cannot be edited.
* @group Props
*/
readonly = input(undefined, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* When present, custom value instead of predefined options can be entered using the editable input field.
* @group Props
*/
editable = input(undefined, { ...(ngDevMode ? { debugName: "editable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Index of the element in tabbing order.
* @group Props
*/
tabindex = input(0, { ...(ngDevMode ? { debugName: "tabindex" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Default text to display when no option is selected.
* @group Props
*/
placeholder = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
/**
* Icon to display in loading state.
* @group Props
*/
loadingIcon = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "loadingIcon" }] : /* istanbul ignore next */ []));
/**
* Placeholder text to show when filter input is empty.
* @group Props
*/
filterPlaceholder = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
/**
* Locale to use in filtering. The default locale is the host environment's current locale.
* @group Props
*/
filterLocale = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "filterLocale" }] : /* istanbul ignore next */ []));
/**
* Identifier of the accessible input element.
* @group Props
*/
inputId = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "inputId" }] : /* istanbul ignore next */ []));
/**
* A property to uniquely identify a value in options.
* @group Props
*/
dataKey = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "dataKey" }] : /* istanbul ignore next */ []));
/**
* When filtering is enabled, filterBy decides which field or fields (comma separated) to search against.
* @group Props
*/
filterBy = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "filterBy" }] : /* istanbul ignore next */ []));
/**
* Fields used when filtering the options, defaults to optionLabel.
* @group Props
*/
filterFields = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "filterFields" }] : /* istanbul ignore next */ []));
/**
* When present, it specifies that the component should automatically get focus on load.
* @group Props
*/
autofocus = input(undefined, { ...(ngDevMode ? { debugName: "autofocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Clears the filter value when hiding the select.
* @group Props
*/
resetFilterOnHide = input(false, { ...(ngDevMode ? { debugName: "resetFilterOnHide" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Whether the selected option will be shown with a check mark.
* @group Props
*/
checkmark = input(false, { ...(ngDevMode ? { debugName: "checkmark" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Icon class of the select icon.
* @group Props
*/
dropdownIcon = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "dropdownIcon" }] : /* istanbul ignore next */ []));
/**
* Whether the select is in loading state.
* @group Props
*/
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Name of the label field of an option.
* @group Props
*/
optionLabel = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "optionLabel" }] : /* istanbul ignore next */ []));
/**
* Name of the value field of an option.
* @group Props
*/
optionValue = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "optionValue" }] : /* istanbul ignore next */ []));
/**
* Name of the disabled field of an option.
* @group Props
*/
optionDisabled = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "optionDisabled" }] : /* istanbul ignore next */ []));
/**
* Name of the label field of an option group.
* @group Props
*/
optionGroupLabel = input('label', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "optionGroupLabel" }] : /* istanbul ignore next */ []));
/**
* Name of the options field of an option group.
* @group Props
*/
optionGroupChildren = input('items', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "optionGroupChildren" }] : /* istanbul ignore next */ []));
/**
* Whether to display options as grouped when nested options are provided.
* @group Props
*/
group = input(undefined, { ...(ngDevMode ? { debugName: "group" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* When enabled, a clear icon is displayed to clear the value.
* @group Props
*/
showClear = input(undefined, { ...(ngDevMode ? { debugName: "showClear" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.
* @group Props
*/
emptyFilterMessage = input('', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "emptyFilterMessage" }] : /* istanbul ignore next */ []));
/**
* Text to display when there is no data. Defaults to global value in i18n translation configuration.
* @group Props
*/
emptyMessage = input('', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
/**
* Defines if data is loaded and interacted with in lazy manner.
* @group Props
*/
lazy = input(false, { ...(ngDevMode ? { debugName: "lazy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Whether the data should be loaded on demand during scroll.
* @group Props
*/
virtualScroll = input(undefined, { ...(ngDevMode ? { debugName: "virtualScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Height of an item in the list for VirtualScrolling.
* @group Props
*/
virtualScrollItemSize = input(undefined, { ...(ngDevMode ? { debugName: "virtualScrollItemSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Whether to use the scroller feature. The properties of scroller component can be used like an object in it.
* @group Props
*/
virtualScrollOptions = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "virtualScrollOptions" }] : /* istanbul ignore next */ []));
/**
* Whether to use overlay API feature. The properties of overlay API can be used like an object in it.
* @group Props
*/
overlayOptions = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "overlayOptions" }] : /* istanbul ignore next */ []));
/**
* Defines a string that labels the filter input.
* @group Props
*/
ariaFilterLabel = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaFilterLabel" }] : /* istanbul ignore next */ []));
/**
* Used to define a aria label attribute the current element.
* @group Props
*/
ariaLabel = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
/**
* Establishes relationships between the component and label(s) where its value should be one or more element IDs.
* @group Props
*/
ariaLabelledBy = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []));
/**
* Defines how the items are filtered.
* @group Props
*/
filterMatchMode = input('contains', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "filterMatchMode" }] : /* istanbul ignore next */ []));
/**
* Advisory information to display in a tooltip on hover.
* @group Props
*/
tooltip = input('', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
/**
* Position of the tooltip.
* @group Props
*/
tooltipPosition = input('right', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "tooltipPosition" }] : /* istanbul ignore next */ []));
/**
* Type of CSS position.
* @group Props
*/
tooltipPositionStyle = input('absolute', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "tooltipPositionStyle" }] : /* istanbul ignore next */ []));
/**
* Style class of the tooltip.
* @group Props
*/
tooltipStyleClass = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "tooltipStyleClass" }] : /* istanbul ignore next */ []));
/**
* Fields used when filtering the options, defaults to optionLabel.
* @group Props
*/
focusOnHover = input(true, { ...(ngDevMode ? { debugName: "focusOnHover" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Determines if the option will be selected on focus.
* @group Props
*/
selectOnFocus = input(false, { ...(ngDevMode ? { debugName: "selectOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* When enabled, allows multiple items to be selected.
* @group Props
*/
multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Whether to focus on the first visible or selected element when the overlay panel is shown.
* @group Props
*/
autoOptionFocus = input(false, { ...(ngDevMode ? { debugName: "autoOptionFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Applies focus to the filter element when the overlay is shown.
* @group Props
*/
autofocusFilter = input(true, { ...(ngDevMode ? { debugName: "autofocusFilter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* When specified, filter displays with this value.
* @group Props
*/
filterValue = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "filterValue" }] : /* istanbul ignore next */ []));
/**
* An array of objects to display as the available options.
* @group Props
*/
options = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "options" }] : /* istanbul ignore next */ []));
/**
* 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).
* @defaultValue 'self'
* @group Props
*/
appendTo = input(undefined, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "appendTo" }] : /* istanbul ignore next */ []));
/**
* The motion options.
* @group Props
*/
motionOptions = input(undefined, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "motionOptions" }] : /* istanbul ignore next */ []));
/**
* Callback to invoke when value of select changes.
* @param {SelectChangeEvent} event - custom change event.
* @group Emits
*/
onChange = output();
/**
* Callback to invoke when data is filtered.
* @param {SelectFilterEvent} event - custom filter event.
* @group Emits
*/
onFilter = output();
/**
* Callback to invoke when select gets focus.
* @param {Event} event - Browser event.
* @group Emits
*/
onFocus = output();
/**
* Callback to invoke when select loses focus.
* @param {Event} event - Browser event.
* @group Emits
*/
onBlur = output();
/**
* Callback to invoke when component is clicked.
* @param {MouseEvent} event - Mouse event.
* @group Emits
*/
onClick = output();
/**
* Callback to invoke when select overlay gets visible.
* @param {AnimationEvent} event - Animation event.
* @group Emits
*/
onShow = output();
/**
* Callback to invoke when select overlay gets hidden.
* @param {AnimationEvent} event - Animation event.
* @group Emits
*/
onHide = output();
/**
* Callback to invoke when select clears the value.
* @param {Event} event - Browser event.
* @group Emits
*/
onClear = output();
/**
* Callback to invoke in lazy mode to load new data.
* @param {SelectLazyLoadEvent} event - Lazy load event.
* @group Emits
*/
onLazyLoad = output();
_componentStyle = inject(SelectStyle);
filterViewChild = viewChild('filter', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "filterViewChild" }] : /* istanbul ignore next */ []));
focusInputViewChild = viewChild('focusInput', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "focusInputViewChild" }] : /* istanbul ignore next */ []));
editableInputViewChild = viewChild('editableInput', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "editableInputViewChild" }] : /* istanbul ignore next */ []));
itemsViewChild = viewChild('items', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "itemsViewChild" }] : /* istanbul ignore next */ []));
scroller = viewChild('scroller', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "scroller" }] : /* istanbul ignore next */ []));
overlayViewChild = viewChild('overlay', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "overlayViewChild" }] : /* istanbul ignore next */ []));
firstHiddenFocusableElementOnOverlay = viewChild('firstHiddenFocusableEl', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "firstHiddenFocusableElementOnOverlay" }] : /* istanbul ignore next */ []));
lastHiddenFocusableElementOnOverlay = viewChild('lastHiddenFocusableEl', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "lastHiddenFocusableElementOnOverlay" }] : /* istanbul ignore next */ []));
itemsWrapper;
$appendTo = computed(() => this.appendTo() || this.config.overlayAppendTo(), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$appendTo" }] : /* istanbul ignore next */ []));
/**
* Custom item template.
* @group Templates
*/
itemTemplate = contentChild('item', { ...(ngDevMode ? { debugName: "itemTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom group template.
* @group Templates
*/
groupTemplate = contentChild('group', { ...(ngDevMode ? { debugName: "groupTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom loader template.
* @group Templates
*/
loaderTemplate = contentChild('loader', { ...(ngDevMode ? { debugName: "loaderTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom selected item template.
* @group Templates
*/
selectedItemTemplate = contentChild('selectedItem', { ...(ngDevMode ? { debugName: "selectedItemTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom header template.
* @param {SelectHeaderTemplateContext} context - header context.
* @group Templates
*/
headerTemplate = contentChild('header', { ...(ngDevMode ? { debugName: "headerTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom filter template.
* @group Templates
*/
filterTemplate = contentChild('filter', { ...(ngDevMode ? { debugName: "filterTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom footer template.
* @group Templates
*/
footerTemplate = contentChild('footer', { ...(ngDevMode ? { debugName: "footerTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom empty filter template.
* @group Templates
*/
emptyFilterTemplate = contentChild('emptyfilter', { ...(ngDevMode ? { debugName: "emptyFilterTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom empty template.
* @group Templates
*/
emptyTemplate = contentChild('empty', { ...(ngDevMode ? { debugName: "emptyTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom dropdown icon template.
* @group Templates
*/
dropdownIconTemplate = contentChild('dropdownicon', { ...(ngDevMode ? { debugName: "dropdownIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom loading icon template.
* @group Templates
*/
loadingIconTemplate = contentChild('loadingicon', { ...(ngDevMode ? { debugName: "loadingIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom clear icon template.
* @group Templates
*/
clearIconTemplate = contentChild('clearicon', { ...(ngDevMode ? { debugName: "clearIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom filter icon template.
* @group Templates
*/
filterIconTemplate = contentChild('filtericon', { ...(ngDevMode ? { debugName: "filterIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom on icon template.
* @group Templates
*/
onIconTemplate = contentChild('onicon', { ...(ngDevMode ? { debugName: "onIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom off icon template.
* @group Templates
*/
offIconTemplate = contentChild('officon', { ...(ngDevMode ? { debugName: "offIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
/**
* Custom cancel icon template.
* @group Templates
*/
cancelIconTemplate = contentChild('cancelicon', { ...(ngDevMode ? { debugName: "cancelIconTemplate" } : /* istanbul ignore next */ {}), descendants: false });
filterOptions;
_filterValue = signal(null, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "_filterValue" }] : /* istanbul ignore next */ []));
_placeholder = signal(undefined, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "_placeholder" }] : /* istanbul ignore next */ []));
_options = signal(null, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "_options" }] : /* istanbul ignore next */ []));
value;
hover;
focused = signal(false, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
overlayVisible = signal(false, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "overlayVisible" }] : /* istanbul ignore next */ []));
optionsChanged;
panel;
dimensionsUpdated;
hoveredItem;
selectedOptionUpdated;
searchValue;
searchIndex;
searchTimeout;
previousSearchChar;
currentSearchChar;
preventModelTouched;
focusedOptionIndex = signal(-1, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "focusedOptionIndex" }] : /* istanbul ignore next */ []));
labelId;
listId;
clicked = signal(false, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "clicked" }] : /* istanbul ignore next */ []));
emptyMessageLabel = computed(() => this.emptyMessage() || this.translate(TranslationKeys.EMPTY_MESSAGE), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "emptyMessageLabel" }] : /* istanbul ignore next */ []));
emptyFilterMessageLabel = computed(() => this.emptyFilterMessage() || this.translate(TranslationKeys.EMPTY_FILTER_MESSAGE), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "emptyFilterMessageLabel" }] : /* istanbul ignore next */ []));
isVisibleClearIcon = computed(() => {
if (!this.showClear() || this.$disabled())
return false;
const value = this.modelValue();
if (this.multiple()) {
return Array.isArray(value) && value.length > 0;
}
return value != null && this.hasSelectedOption();
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "isVisibleClearIcon" }] : /* istanbul ignore next */ []));
get listLabel() {
return this.translate(TranslationKeys.ARIA, 'listLabel');
}
focusedOptionId = computed(() => (this.focusedOptionIndex() !== -1 ? `${this.$id()}_${this.focusedOptionIndex()}` : null), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "focusedOptionId" }] : /* istanbul ignore next */ []));
visibleOptions = computed(() => {
const options = this.getAllVisibleAndNonVisibleOptions();
if (this._filterValue()) {
const _filterBy = this.filterBy() || this.optionLabel();
const filteredOptions = !_filterBy && !this.filterFields() && !this.optionValue()
? this._options()?.filter((option) => {
if (option.label) {
return option.label.toString().toLowerCase().indexOf(this._filterValue().toLowerCase().trim()) !== -1;
}
return option.toString().toLowerCase().indexOf(this._filterValue().toLowerCase().trim()) !== -1;
})
: this.filterService.filter(options, this.searchFields(), this._filterValue().trim(), this.filterMatchMode(), this.filterLocale());
if (this.group()) {
const optionGroups = this._options() || [];
const filtered = [];
optionGroups.forEach((group) => {
const groupChildren = this.getOptionGroupChildren(group);
const filteredItems = groupChildren.filter((item) => filteredOptions?.includes(item));
if (filteredItems.length > 0)
filtered.push({
...group,
[typeof this.optionGroupChildren() === 'string' ? this.optionGroupChildren() : 'items']: [...filteredItems]
});
});
return this.flatOptions(filtered);
}
return filteredOptions;
}
return options;
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "visibleOptions" }] : /* istanbul ignore next */ []));
label = computed(() => {
if (this.multiple()) {
const currentValue = this.modelValue();
if (!Array.isArray(currentValue) || currentValue.length === 0) {
return this.placeholder() || 'p-emptylabel';
}
const options = this.getAllVisibleAndNonVisibleOptions();
const labels = currentValue
.map((val) => {
const opt = options.find((o) => !this.isOptionGroup(o) && equals(val, this.getOptionValue(o), this.equalityKey()));
return opt ? this.getOptionLabel(opt) : String(val);
})
.filter(Boolean);
return labels.join(', ');
}
// use getAllVisibleAndNonVisibleOptions verses just visible options
// 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
const options = this.getAllVisibleAndNonVisibleOptions();
// use isOptionEqualsModelValue for the use case where the dropdown is initalized with a disabled option
const selectedOptionIndex = options.findIndex((option) => {
const isEqual = this.isOptionValueEqualsModelValue(option);
return isEqual;
});
if (selectedOptionIndex !== -1) {
const selectedOption = options[selectedOptionIndex];
// Always show the label for selected options, even if disabled
return this.getOptionLabel(selectedOption);
}
return this.placeholder() || 'p-emptylabel';
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
$ariaLabel = computed(() => {
return this.ariaLabel() || (this.label() === 'p-emptylabel' ? undefined : this.label());
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$ariaLabel" }] : /* istanbul ignore next */ []));
$ariaMultiselectable = computed(() => this.multiple() || undefined, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$ariaMultiselectable" }] : /* istanbul ignore next */ []));
$placeholder = computed(() => {
const modelVal = this.modelValue();
return modelVal === undefined || modelVal === null ? this.placeholder() || this._placeholder() : undefined;
}, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$placeholder" }] : /* istanbul ignore next */ []));
$required = computed(() => (this.required() ? '' : undefined), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$required" }] : /* istanbul ignore next */ []));
$readonly = computed(() => (this.readonly() ? '' : undefined), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$readonly" }] : /* istanbul ignore next */ []));
$disabledAttr = computed(() => (this.$disabled() ? '' : undefined), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$disabledAttr" }] : /* istanbul ignore next */ []));
$tabindex = computed(() => (!this.$disabled() ? this.tabindex() : -1), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$tabindex" }] : /* istanbul ignore next */ []));
filterInputValue = computed(() => this._filterValue() || '', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "filterInputValue" }] : /* istanbul ignore next */ []));
get $ariaActivedescendant() {
return this.focused() ? this.focusedOptionId() : undefined;
}
get $ariaExpanded() {
return this.overlayVisible();
}
$ariaControls = computed(() => (this.overlayVisible() ? this.$id() + '_list' : null), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$ariaControls" }] : /* istanbul ignore next */ []));
showEmptyFilterMessage = computed(() => this._filterValue() && this.isEmpty(), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "showEmptyFilterMessage" }] : /* istanbul ignore next */ []));
showEmptyMessage = computed(() => !this._filterValue() && this.isEmpty(), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "showEmptyMessage" }] : /* istanbul ignore next */ []));
hasEmptyTemplate = computed(() => this.emptyFilterTemplate() || this.emptyTemplate(), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "hasEmptyTemplate" }] : /* istanbul ignore next */ []));
$ariaOwns = computed(() => this.$id() + '_list', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "$ariaOwns" }] : /* istanbul ignore next */ []));
get selectedItemContext() {
return { $implicit: this.selectedOption() };
}
get clearIconContext() {
return { class: this.cx('clearIcon') ?? '' };
}
get dropdownIconContext() {
return { class: this.cx('dropdownIcon') ?? '' };
}
get filterTemplateContext() {
return { options: this.filterOptions ?? {} };
}
get defaultBuildInItemsContext() {
return { $implicit: this.visibleOptions(), options: {} };
}
getBuildInItemsContext(items, scrollerOptions) {
return { $implicit: items, options: scrollerOptions };
}
getLoaderContext(scrollerOptions) {
return { options: scrollerOptions };
}
getItemSizeStyle(scrollerOptions) {
return { height: scrollerOptions.itemSize + 'px' };
}
getGroupContext(optionGroup) {
return { $implicit: optionGroup };
}
selectedOption = signal(null, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []));
constructor() {
super();
effect(() => {
const modelValue = this.modelValue();
const visibleOptions = this.visibleOptions();
if (visibleOptions && isNotEmpty(visibleOptions)) {
const selectedOptionIndex = this.findSelectedOptionIndex();
if (selectedOptionIndex !== -1 || modelValue === undefined || (typeof modelValue === 'string' && modelValue.length === 0) || this.isModelValueNotSet() || this.editable()) {
this.selectedOption.set(visibleOptions[selectedOptionIndex]);
}
else {
// If no valid selected option found but we have a model value,
// try to find the option including disabled ones for template display
const disabledSelectedIndex = visibleOptions.findIndex((option) => this.isSelected(option));
if (disabledSelectedIndex !== -1) {
this.selectedOption.set(visibleOptions[disabledSelectedIndex]);
}
}
}
if (isEmpty(visibleOptions) && (modelValue === undefined || this.isModelValueNotSet()) && isNotEmpty(this.selectedOption())) {
this.selectedOption.set(null);
}
if (modelValue !== undefined && this.editable()) {
this.updateEditableLabel();
}
});
// Handle filterValue input changes
effect(() => {
const filterVal = this.filterValue();
if (filterVal !== undefined) {
this._filterValue.set(filterVal);
}
});
// Handle options input changes with deepEquals check
effect(() => {
const opts = this.options();
if (!deepEquals(opts, this._options())) {
this._options.set(opts ?? null);
this.optionsChanged = true;
}
});
}
isModelValueNotSet() {
return this.modelValue() === null && !this.isOptionValueEqualsModelValue(this.selectedOption());
}
getAllVisibleAndNonVisibleOptions() {
return this.group() ? this.flatOptions(this._options()) : this._options() || [];
}
onInit() {
this.autoUpdateModel();
if (this.filterBy()) {
this.filterOptions = {
filter: (value) => this.onFilterInputChange(value),
reset: () => this.resetFilter()
};
}
}
onAfterViewC