import { KbqTreeSelectModule } from '@koobiq/components/tree-select';

KbqTreeSelect

componentCopy link to KbqTreeSelect
@Component({ selector: 'kbq-tree-select', exportAs: 'kbqTreeSelect' })
class KbqTreeSelect<T = any, K = T> extends KbqAbstractSelect implements ControlValueAccessor, KbqFormFieldControl<KbqTreeOption>, CanUpdateErrorState, KbqSiblingPopup {
readonly hiddenItemsText = input<string | undefined>();
readonly hiddenItemsTextFormatter = input<(hiddenItemsText: string, hiddenItems: number) => string>(
(hiddenItemsText, hiddenItems) => hiddenItemsText.replace('{{ number }}', hiddenItems.toString())
);
readonly panelClass = input<| string | string[] | Set<string> | { [key: string]: any; }>();
readonly backdropClass = input<string>(
'cdk-overlay-transparent-backdrop'
);
readonly ariaLabel = input<string | null>(null, {
alias: 'aria-label'
});
readonly ariaLabelledby = input<string | null>(null, {
alias: 'aria-labelledby'
});
readonly errorStateMatcher = input<ErrorStateMatcher>();
readonly sortComparator = input<KbqTreeSelectSortComparator>();
readonly clearPredicate = input<(node: T) => boolean>(
this.defaultOptions?.clearPredicate ?? ((node) => !this.isNodeDisabled(node))
);
readonly multiline = input<boolean>(false);
readonly placeholder = input<string>();
readonly required = input<boolean>(false);
multiple = input<boolean>(false);
autoSelect = input<boolean>(true);
readonly selectAllToggle = input<boolean>(false);
readonly selectAll = input<boolean>(false);
readonly id = input<string | undefined>();
readonly hasBackdrop = input<boolean>(false);
readonly disabled = input<boolean>(false);
selectAllHandler = input<((event: KeyboardEvent, select: KbqTreeSelect<T, K>) => void) | undefined>();
readonly panelMinWidth = input<KbqPanelMinWidth>(
this.defaultOptions?.panelMinWidth === undefined
? KBQ_PANEL_DEFAULT_MIN_WIDTH
: this.defaultOptions.panelMinWidth
);
readonly panelWidth = input<KbqPanelWidth>(
this.defaultOptions?.panelWidth ?? null
);
readonly panelMaxWidth = input<KbqPanelMaxWidth>(
this.defaultOptions?.panelMaxWidth === undefined ? null : this.defaultOptions.panelMaxWidth
);
readonly panelMaxHeight = input<KbqPanelMaxHeight>(
this.defaultOptions?.panelMaxHeight === undefined ? null : this.defaultOptions.panelMaxHeight
);
readonly searchMinOptionsThreshold = input<'auto' | number | undefined>();
readonly selectionChange = output<KbqTreeSelectChange>();
readonly onSelectAll = output<KbqSelectAllEvent<KbqTreeOption<T>, KbqTreeSelect<T, K>>>();
elementRef: ElementRef<HTMLElement>;
defaultErrorStateMatcher: ErrorStateMatcher;
parentForm: NgForm | null;
parentFormGroup: FormGroupDirective | null;
ngControl: NgControl | null;
readonly errorState: Signal<boolean>;
controlType: string;
readonly isNativeLabelSupported: false;
readonly hiddenItems: WritableSignal<number>;
triggerFontSize: number;
selectionModel: SelectionModel<T>;
scrollStrategy: ScrollStrategy;
positions: ConnectedPosition[];
readonly trigger: Signal<ElementRef<any>>;
readonly panel: Signal<ElementRef<any> | undefined>;
readonly customTrigger: Signal<KbqSelectTrigger | undefined>;
readonly customMatcher: Signal<KbqSelectMatcher | undefined>;
readonly customTagTemplateRef: Signal<TemplateRef<any> | undefined>;
readonly tree: Signal<KbqTreeSelection<T, K> | undefined>;
readonly search: Signal<KbqSelectSearch | undefined>;
readonly openedChange: EventEmitter<boolean>;
readonly openedStream: Observable<void>;
readonly closedStream: Observable<void>;
readonly optionSelectionChanges: Observable<KbqTreeSelectChange>;
readonly userInteractionChanges: Observable<void>;
readonly value: Signal<any>;
readonly focused: Signal<boolean>;
get multiSelection(): boolean;
get panelOpen(): boolean;
get isAttached(): boolean;
isEmptySearchResult: boolean;
triggerValues: KbqTreeSelectTriggerValue[];
get selected(): T | T[];
get selectedValues(): any;
get triggerValue(): string;
readonly empty: Signal<boolean>;
updateErrorState(): void;
toggle(): void;
open(): void;
close(): void;
onFocus(): void;
onBlur(): void;
onAttached(): void;
focus(): void;
onRemoveSelectedOption(
selectedOption: KbqTreeSelectTriggerValue,
$event: Event
): void;
triggerKeydownHandler(event: KeyboardEvent): void;
panelKeydownHandler(event: KeyboardEvent): void;
}
hiddenItemsTextinputCopy link to hiddenItemsTextstring | undefined

Text of the counter of the selected items that do not fit into the trigger. {{ number }} is replaced with their number.

Left unset, the text follows the active locale (select.hiddenItemsText); set, it wins over the locale and survives a locale change.

hiddenItemsTextFormatterinputCopy link to hiddenItemsTextFormatter(hiddenItemsText: string, hiddenItems: number) => string

Formats the counter of the items that do not fit into the trigger.

panelClassinputCopy link to panelClass| string | string[] | Set<string> | { [key: string]: any; }

Classes to be passed to the select panel. Supports the same syntax as the [class] binding.

aria-labelinputCopy link to aria-labelstring | null

Name of the control, for when no element on the page carries it. Defaults to the placeholder.

Prefer aria-labelledby and point it at visible text: a name that duplicates a visible label is one more string to keep in sync, and a name with no visible counterpart cannot be spoken back by voice control (WCAG 2.5.3).

aria-labelledbyinputCopy link to aria-labelledbystring | null

Id of the element that names the control. Defaults to the kbq-label of a wrapping kbq-form-field.

A role="combobox" element takes its name from the author only, so neither the placeholder nor the selected values name it, and the <label for> of the form field names labelable elements only, which a custom control is not. Without a form-field label, point this at whatever visible text names the control.

errorStateMatcherinputCopy link to errorStateMatcherErrorStateMatcher

Object used to control when error messages are shown.

sortComparatorinputCopy link to sortComparatorKbqTreeSelectSortComparator

Function used to sort the values in a select in multiple mode, by default their order in the panel. Follows the same logic as Array.prototype.sort. Receives two selected data nodes and every data node of the tree in panel order, collapsed branches included โ€” a node in a collapsed branch has no option.

clearPredicateinputCopy link to clearPredicate(node: T) => boolean

Decides which selected nodes the projected KbqCleaner removes: return true to clear the node, false to keep it. Receives the data node, not the option โ€” a node in a collapsed branch has no option. Disabled nodes are kept by default. Bind a stable reference โ€” a new function on every change detection re-runs the predicate over the whole selection.

Not consulted by writeValue / reset(), which always clear everything. The parameter type becomes the select's T in a template: type it with the tree's node, not with an option.

multilineinputCopy link to multilineboolean

Whether to use a multiline matcher or not. Default is false

placeholderinputCopy link to placeholderstring

Placeholder shown in the trigger while nothing is selected.

requiredinputCopy link to requiredboolean

Whether the select is required.

multipleinputCopy link to multipleboolean

Whether multiple nodes can be selected. Cannot be changed once the selection model exists.

autoSelectinputCopy link to autoSelectboolean

Whether moving the active node selects it. Always off in multiple selection.

selectAllToggleinputCopy link to selectAllToggleboolean

When true, a repeated Ctrl/Cmd+A deselects all options. Off by default (Ctrl+A only selects).

selectAllinputCopy link to selectAllboolean

Whether to render the "select all" master checkbox above the tree. Multiple selection only.

The row acts on the nodes the user can actually toggle โ€” enabled and selectable. Without a search query that covers the whole data set, collapsed branches included; while a query is active it covers only the matches. Enabling it also makes Ctrl/Cmd + A a two-way toggle, so the shortcut and the checkbox never disagree (selectAllToggle is implied).

idinputCopy link to idstring | undefined

Unique identifier of the select, generated when not provided.

hasBackdropinputCopy link to hasBackdropboolean

Whether the overlay panel is rendered on top of a backdrop.

disabledinputCopy link to disabledboolean

Whether the select is disabled. Also set by the bound form control.

selectAllHandlerinputCopy link to selectAllHandler((event: KeyboardEvent, select: KbqTreeSelect<T, K>) => void) | undefined

Function for handling the combination Ctrl + A (select all). By default, the internal handler is used.

panelMinWidthinputCopy link to panelMinWidthKbqPanelMinWidth

Minimum width of the panel. If minWidth is larger than window width, it will be ignored.

panelWidthinputCopy link to panelWidthKbqPanelWidth

Width of the panel. If set to auto, the panel will match the trigger width, but will never be narrower than panelMinWidth. If set to null or an empty string, the panel will grow to match the longest option's text. Any other value is used as an exact width, and panelMinWidth is not applied.

panelMaxWidthinputCopy link to panelMaxWidthKbqPanelMaxWidth

Maximum width of the panel in pixels. Caps how far the panel grows with its content โ€” it never makes the panel narrower than the trigger, and never clamps an explicit panelWidth. When null, the --kbq-panel-size-width-max token applies.

panelMaxHeightinputCopy link to panelMaxHeightKbqPanelMaxHeight

Maximum height of the panel's scrollable option list, in pixels. Applied as the --kbq-select-panel-size-max-height custom property on the panel.

The search field and the footer sit outside the scrollable area and add to the panel's total height. When null, the token default (256px) applies.

searchMinOptionsThresholdinputCopy link to searchMinOptionsThreshold'auto' | number | undefined

Controls when the search functionality is displayed based on the number of available options.

Automatically enables search hiding if value provided, even if defaultOptions.searchMinOptionsThreshold is provided. Defaults to undefined.

localeOverridesinputCopy link to localeOverridesKbqPartialLocaleData | undefined

Localized strings for this element and its subtree, keyed by locale section. Every key is optional at every depth.

selectionChangeoutputCopy link to selectionChangeKbqTreeSelectChange

Event emitted when the selected value has been changed by the user.

onSelectAlloutputCopy link to onSelectAllKbqSelectAllEvent<KbqTreeOption<T>, KbqTreeSelect<T, K>>

Event emitted whenever the tree's selectAllOptions() runs โ€” a click on the selectAll master checkbox, the Ctrl/Cmd + A shortcut, or a custom selectAllHandler that delegates to it.

errorStateCopy link to errorStateSignal<boolean>

Whether the component is in an error state.

controlTypeCopy link to controlTypestring

A name for this control that can be used by kbq-form-field.

isNativeLabelSupportedCopy link to isNativeLabelSupportedfalse

A kbq-tree-select is not a native labelable element, so the form-field's <label for> cannot associate with it. The control is named through aria-labelledby instead.

hiddenItemsCopy link to hiddenItemsWritableSignal<number>

Number of the selected items that do not fit into the trigger.

triggerFontSizeCopy link to triggerFontSizenumber

The cached font-size of the trigger element.

selectionModelCopy link to selectionModelSelectionModel<T>

Deals with the selection logic. The projected kbq-tree-selection shares the same instance.

T is the type of the data nodes, the same as the projected tree's. A template infers it from [clearPredicate] alone, apart from the tree; a query names it: viewChild.required<KbqTreeSelect<Node>>(KbqTreeSelect), and a select whose tree control has a trackBy names the key type too: KbqTreeSelect<Node, string>.

scrollStrategyCopy link to scrollStrategyScrollStrategy

Strategy that will be used to handle scrolling while the select panel is open.

positionsCopy link to positionsConnectedPosition[]

Opens the panel below the trigger, falling back to above it when it does not fit.

A third position is appended at runtime by updatePanelAnchor: a multiline trigger that has grown taller than the panel gets it anchored to its first row and drawn over the rest of it.

triggerCopy link to triggerSignal<ElementRef<any>>

Trigger - is a clickable field to open select dropdown panel

panelCopy link to panelSignal<ElementRef<any> | undefined>

Reference to the overlay panel element.

customTriggerCopy link to customTriggerSignal<KbqSelectTrigger | undefined>

User-supplied override of the trigger element.

openedChangeCopy link to openedChangeEventEmitter<boolean>

Event emitted when the select panel has been toggled. Also serves as the openedChange member of the KbqSiblingPopup contract โ€” a tooltip sharing this element's host reacts to it, so its emission timing (gated on panelDoneAnimatingStream, see ngOnInit) matters beyond this output's original consumers.

openedStreamCopy link to openedStreamObservable<void>

Event emitted when the select has been opened.

closedStreamCopy link to closedStreamObservable<void>

Event emitted when the select has been closed.

optionSelectionChangesCopy link to optionSelectionChangesObservable<KbqTreeSelectChange>

Combined stream of all of the child options' change events.

userInteractionChangesCopy link to userInteractionChangesObservable<void>

Combined stream of all of the child options userInteraction events.

valueCopy link to valueSignal<any>

Values of the selected nodes: an array in multiple mode.

focusedCopy link to focusedSignal<boolean>

Whether the select is focused.

multiSelectionCopy link to multiSelectionboolean

Whether multiple choice is enabled or not. True if multiple or multiline

isAttachedCopy link to isAttachedboolean

Whether the overlay panel is currently on screen. Part of the KbqSiblingPopup contract.

emptyCopy link to emptySignal<boolean>

Whether no node is selected.

close()Copy link to close()void

Closes the overlay panel and focuses the host element.

onBlur()Copy link to onBlur()void

Calls the touched callback only if the panel is closed. Otherwise, the trigger will "blur" to the panel when it opens, causing a false positive.

onAttached()Copy link to onAttached()void

Callback that is invoked when the overlay panel has been attached.

onRemoveSelectedOption()Copy link to onRemoveSelectedOption()void

Removes an option from the selection through the trailing icon of its tag in the trigger.

KbqTreeSelectChange

classCopy link to KbqTreeSelectChange

Change event object that is emitted when the select value has changed.

class KbqTreeSelectChange<T = any> {
source: KbqTreeSelect<any, any>;
value: T;
isUserInput: boolean;
values?: unknown[];
constructor(
source: KbqTreeSelect<any, any>,
value: T,
isUserInput?: boolean,
values?: unknown[]
);
}
sourceCopy link to sourceKbqTreeSelect<any, any>

Select the change comes from.

valueCopy link to valueT

Option the change is about โ€” a KbqTreeOption whenever the changed node is rendered, and the raw value of the node when it is not. null when the change is not about a single option, which today means the cleaner was activated; values then carries the nodes it removed.

isUserInputCopy link to isUserInputboolean

Whether the change was made by the user rather than written to the model.

valuesoptionalCopy link to valuesunknown[]

Every option the change is about, when it covers more than one.

constructor()Copy link to constructor()
Parameters
sourceKbqTreeSelect<any, any>

Select the change comes from.

valueT

Option the change is about โ€” a KbqTreeOption whenever the changed node is rendered, and the raw value of the node when it is not. null when the change is not about a single option, which today means the cleaner was activated; values then carries the nodes it removed.

isUserInput?boolean

Whether the change was made by the user rather than written to the model.

values?unknown[]

Every option the change is about, when it covers more than one.

KbqTreeSelectOptions

typeCopy link to KbqTreeSelectOptions

Options for the kbq-tree-select that can be configured using the KBQ_TREE_SELECT_OPTIONS injection token.

type KbqTreeSelectOptions = Partial<{
panelWidth: KbqPanelWidth;
panelMinWidth: KbqPanelMinWidth;
panelMaxWidth: KbqPanelMaxWidth;
panelMaxHeight: KbqPanelMaxHeight;
searchMinOptionsThreshold: 'auto' | number;
clearPredicate: (node: any) => boolean;
}>;
panelWidthoptionalCopy link to panelWidthKbqPanelWidth

Width of the panel. If set to auto, the panel will match the trigger width. If set to null or an empty string, the panel will grow to match the longest option's text.

panelMinWidthoptionalCopy link to panelMinWidthKbqPanelMinWidth

Minimum width of the panel. If minWidth is larger than window width or property set to null, it will be ignored.

panelMaxWidthoptionalCopy link to panelMaxWidthKbqPanelMaxWidth

Maximum width of the panel. Caps growth by content only โ€” it never overrides the trigger width or an explicit panelWidth. If null, the --kbq-panel-size-width-max token applies.

panelMaxHeightoptionalCopy link to panelMaxHeightKbqPanelMaxHeight

Maximum height of the panel's scrollable option list. Does not include the search field or the footer. If null, the --kbq-select-panel-size-max-height token applies.

searchMinOptionsThresholdoptionalCopy link to searchMinOptionsThreshold'auto' | number

Whether to enable hiding search by default if options is less than minimum.

  • 'auto' uses KBQ_SELECT_SEARCH_MIN_OPTIONS_THRESHOLD as min value.
  • number - will enables search hiding and uses value as min.
clearPredicateoptionalCopy link to clearPredicate(node: any) => boolean

Decides which selected nodes the projected KbqCleaner removes. Disabled nodes are kept when this is not set. Overridden per instance by the clearPredicate attribute.

KbqTreeSelectSortComparator

typeCopy link to KbqTreeSelectSortComparator

Orders the values of a tree select in multiple mode, as Array.prototype.sort does. Receives two selected data nodes and every data node of the tree in panel order.

type KbqTreeSelectSortComparator<T = any> = (a: T, b: T, nodes: T[]) => number;

KbqTreeSelectTriggerValue

typeCopy link to KbqTreeSelectTriggerValue

Tree select trigger value type.

type KbqTreeSelectTriggerValue = {
disabled: boolean;
value: string;
viewValue: string;
};

KBQ_TREE_SELECT_OPTIONS

constCopy link to KBQ_TREE_SELECT_OPTIONS

Injection token that can be used to provide the default options for the kbq-tree-select.

const KBQ_TREE_SELECT_OPTIONS: InjectionToken<KbqTreeSelectOptions>;

kbqTreeSelectOptionsProvider

constCopy link to kbqTreeSelectOptionsProvider

Utility provider for KBQ_TREE_SELECT_OPTIONS.

const kbqTreeSelectOptionsProvider: (
options: KbqTreeSelectOptions
) => Provider;
Suggestions for improvement
If you found a mistake or want to improve the article, create an issue on GitHub.