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,000 lines (996 loc) 134 kB
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