QueryListComponent
Query-driven list component that executes a search query and renders the results using a consumer-provided item template.
The component is a thin orchestration layer on top of yuv-list: it handles the full query lifecycle (executing, paginating, refreshing), exposes a typed result set via the optional transformer input, and delegates all keyboard navigation, selection, and accessibility concerns to the inner ListComponent.
Key Features:
-
Accepts a
SearchQueryobject or a raw CMIS query string -
Optional
transformerfunction maps rawSearchResultItem[]to any custom typeT -
Built-in server-side pagination via Angular Material
mat-paginator -
Multi-selection with mouse drag (
DragSelectDirective) and keyboard modifiers -
“Drop-in” items prepended to the result set for optimistic UI updates
-
Busy state signal for loading indicators
-
Exposes a slim imperative API (
select,clear,refresh,goToPage, …) so parents can drive the list programmatically
Content Projection Slots:
-
#yuvQueryListItem— required;ng-templateused to render each result item. Receives the (optionally transformed) item as$implicit. -
#yuvQueryListEmpty— optional;ng-templateshown when the result set is empty.
Basic usage:
Example :
<yuv-query-list [query]="query" (itemSelect)="onSelect($event)">
<ng-template #yuvQueryListItem let-item>
<span>{{ item.title }}</span>
</ng-template>
</yuv-query-list>With transformer and empty state:
Example :
<yuv-query-list [query]="query" [transformer]="toViewModel" (itemSelect)="onSelect($event)">
<ng-template #yuvQueryListItem let-item>
<yuv-list-tile>
<ng-template #titleSlot>{{ item.title }}</ng-template>
<ng-template #descriptionSlot>{{ item.modified }}</ng-template>
</yuv-list-tile>
</ng-template>
<ng-template #yuvQueryListEmpty>
<p>No results found.</p>
</ng-template>
</yuv-query-list>Example :
toViewModel = (items: SearchResultItem[]) =>
items.map(item => ({
title: item.fields.get(BaseObjectTypeField.OBJECT_ID),
modified: item.fields.get(BaseObjectTypeField.MODIFICATION_DATE)
}));Example :
Defaults to `any` when no transformer is provided.Component Metadata
Section titled “Component Metadata”Selector: yuv-query-list
Standalone: No
Inputs
Section titled “Inputs”autoSelect
Section titled “autoSelect”Type: boolean, BooleanInput
Default Value: false, { transform: (value: BooleanInput) => coerceBooleanProperty(value) }
Automatically selects an item when the list is first rendered.Forwarded to the inner ListComponent. The selection logic runs once after the initial query result is displayed and follows this priority:1. The first non-disabled item that already carries the selected attribute.2. If no such item exists and autoSelect is true, the item at index 0.Accepts any truthy string in addition to a real boolean so it can be set as a plain HTML attribute: <yuv-query-list autoSelect>.
enableDragSelect
Section titled “enableDragSelect”Type: boolean
Default Value: true
Enables mouse drag-to-select on list items.When true and multiselect is also true, the user can click and drag across items to select a range without holding Shift. Powered by DragSelectDirective. Automatically disabled on touch devices regardless of this input value.
idProperty
Section titled “idProperty”Type: string | null
Default Value: null
Property name on the (transformed) item to use as a stable unique identifier.When provided, the template renderer uses this property for @for tracking instead of the item’s position index, which preserves DOM nodes and component state when the list is refreshed with partially overlapping results.If omitted, the zero-based index is used as the tracking key.
includePermissions
Section titled “includePermissions”Type: boolean
Default Value: false
Whether to include permission information in CMIS search results. When true, the third parameter of searchCmis() is set, causing the backend to return permission data alongside each item.
multiselect
Section titled “multiselect”Type: boolean
Default Value: false
Enables multi-selection mode.When true, the user can hold Shift or Ctrl to extend or toggle the selection, and drag-to-select becomes available (if enableDragSelect is also true). Forwarded to the inner ListComponent.
pageSize
Section titled “pageSize”Type: number
Default Value: SearchService.DEFAULT_QUERY_SIZE
Number of items to request per page from the search service.Controls the size parameter of each search request. When the total result count exceeds this value, pagination controls are shown and the user can navigate between pages via changePage() / goToPage().
preventChangeUntil
Section titled “preventChangeUntil”Type: () => boolean
Default Value: () => false
Guard function that temporarily blocks all selection changes.Forwarded directly to the inner ListComponent. As long as the returned predicate evaluates to true, any attempt to change the selection — via click, keyboard, or the programmatic API — is silently ignored. Useful when the parent has unsaved changes tied to the current selection and needs to prevent the user from accidentally navigating away.
Type: SearchQuery | string | null
The search query to execute.Accepts either a structured SearchQuery object (field filters, sort orders, etc.) or a raw CMIS query string. The query is re-executed reactively every time this input changes. Set to null or undefined to clear the list without triggering a new request.
selfHandleSelection
Section titled “selfHandleSelection”Type: boolean
Default Value: false
Delegates visual selection and focus state rendering to the parent component.When false (default), yuv-list applies CSS classes for selected and active states automatically. When true, those signals are still updated but the host receives the self-handle-selection CSS class, allowing the parent to apply its own visual treatment. Forwarded to the inner ListComponent.
Outputs
Section titled “Outputs”dragSelectChange
Section titled “dragSelectChange”Type: number[]
Emits the live selection indices while the user is actively dragging to select.Fires continuously during a drag operation (before the drag is released), allowing the parent to show a live preview of what will be selected. Once the drag ends, itemSelect fires with the final committed selection.
itemDoubleClick
Section titled “itemDoubleClick”Type: number
Emits the zero-based index of an item when it is double-clicked.The inner list operates with selfHandleClick mode when double-click is active, so single clicks do not immediately trigger itemSelect. The parent should listen to both itemSelect (for single-click selection) and this event (for double-click actions like opening a detail view).
itemSelect
Section titled “itemSelect”Type: number[]
Emits the current selection as an array of zero-based item indices whenever the selection changes — via click, drag, keyboard, or programmatic API calls.An empty array signals that the selection has been cleared.
queryResult
Section titled “queryResult”Type: { totalCount: number; items: SearchResultItem[] }
Emits once per query execution when the search result arrives, providing the total count of matching items and the raw result page.Use this to update external counters, breadcrumbs, or analytics — without having to execute a separate count query. Note that totalCount reflects the server-side total, not just the number of items on the current page.
Properties
Section titled “Properties”Type: unknown
Default Value: signal<boolean>(false)
Indicates whether a search request is currently in flight.Set to true immediately before a query or page request is dispatched to the search service, and back to false once the response (or error) arrives. Bind this to a loading indicator or BusyOverlayDirective in the parent template:Example :
<yuv-query-list #qList ...>...</yuv-query-list><yuv-busy-overlay [active]="qList.busy()" />dropInSize
Section titled “dropInSize”Type: unknown
Default Value: computed(() => this.#dropInItems().length)
Number of drop-in items currently prepended to the result list.Derived from the internal #dropInItems signal. Exposed publicly so the template and parent components can easily check whether any temporary items are present (e.g. to show a visual indicator or adjust layout) without accessing internal state.
emptyTemplate
Section titled “emptyTemplate”Type: unknown
Default Value: contentChild<TemplateRef<any>>('yuvQueryListEmpty')
Reference to the optional #yuvQueryListEmpty ng-template projected by the consumer.When provided, this template is rendered in place of the list whenever the query returns zero items. If omitted, nothing is shown for the empty state.Example :
<ng-template #yuvQueryListEmpty> <p>No results found.</p></ng-template>isTouchDevice
Section titled “isTouchDevice”Type: unknown
Default Value: this.#device.isTouchEnabled
Whether the current device has touch input enabled.Sourced from DeviceService. Used in the template to conditionally disable drag-to-select, which is not suitable for touch interactions.
itemTemplate
Section titled “itemTemplate”Type: unknown
Default Value: contentChild<TemplateRef<any>>('yuvQueryListItem')
Reference to the #yuvQueryListItem ng-template projected by the consumer.This template is used to render each individual item in the list. The template receives the (optionally transformed) item as the $implicit context variable:Example :
<ng-template #yuvQueryListItem let-item>{{ item.title }}</ng-template>Type: unknown
Default Value: viewChild.required<ListComponent>('list')
Reference to the inner ListComponent instance.Used internally to delegate imperative operations (select, clear, focus, …). Can also be accessed from the parent via a @ViewChild on yuv-query-list if fine-grained control over the inner list is needed, though the public API methods on this component are preferred.
pagination
Section titled “pagination”Type: unknown
Default Value: signal<Pagination | undefined>(undefined)
Current pagination state. Set to a Pagination object when the last query result contained multiple pages; undefined when all results fit on one page or no query has been executed yet.Drives the [class.pagination] host binding so the template can conditionally render the mat-paginator footer.
resultItems
Section titled “resultItems”Type: unknown
Default Value: computed<T[]>(() => { const items = this.#items(); const updates = this.#listItemUpdates(); const transformer = this.transformer(); const transformedResult = transformer ? transformer(items) : (items as unknown as T[]); const dropIns = this.#dropInItems(); let merged: T[]; const idProp = this.idProperty(); if (dropIns.length > 0 && idProp) { // Deduplicate: filter out server results that already appear as drop-in items const dropInIds = new Set(dropIns.map((item) => (item as Record<string, unknown>)[idProp])); const filtered = transformedResult.filter((item) => !dropInIds.has((item as Record<string, unknown>)[idProp])); merged = [...dropIns, ...filtered]; } else { merged = [...dropIns, ...transformedResult]; } // apply updates to transformed result Object.keys(updates).forEach((index) => { merged[Number(index)] = updates[Number(index)]; }); return merged; })
The final list of items rendered by the template.Computed from three sources, merged in this order:1. Drop-in items (#dropInItems) — temporary items prepended to the list, e.g. newly created objects that should appear before they match the query.2. Transformed query results — raw SearchResultItem[] passed through the optional transformer function (or cast directly to T[] if none is provided).3. Optimistic updates (#listItemUpdates) — per-index overrides applied on top of the merged list, allowing individual items to be patched without re-fetching.Re-evaluates automatically whenever any of the three sources change.
transformer
Section titled “transformer”Type: unknown
Default Value: input<((items: SearchResultItem[]) => T[]) | null>()
Optional mapping function applied to the raw SearchResultItem[] returned by the search service before the results are rendered.Use this to project only the fields your template needs, compute derived properties, or convert dates/enums to display-friendly values. The generic type parameter T of the component is inferred from the return type of this function.If omitted, raw SearchResultItem objects are passed to the item template as-is.Example :
transformer = (items: SearchResultItem[]) => items.map(item => ({ id: item.fields.get(BaseObjectTypeField.OBJECT_ID) as string, title: item.fields.get('cm:name') as string }));Methods
Section titled “Methods”changePage
Section titled “changePage”Handles a page-change event emitted by the mat-paginator.Converts the zero-based pageEvent.pageIndex to the one-based page number expected by goToPage() and delegates the request.Bound to (page) on the mat-paginator in the template.
changePage(pageEvent: PageEvent): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| pageEvent | PageEvent |
Clears the current selection and resets the active keyboard-focus index.If the selection is already empty, the method is a no-op. The preventChangeUntil guard is respected — if the guard returns true, the clear is blocked.Example :
when the parent needs to reset state programmatically without triggering downstream reactions.clear(silent: unknown): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| silent | unknown |
dropItems
Section titled “dropItems”Prepends a set of temporary items to the top of the result list.Drop-in items appear before all query results and are visually distinguished by the template (e.g. a highlighted background). They participate in selection and drag-to-select exactly like regular items.The existing selection indices are automatically shifted by items.length so that the currently selected query-result items remain selected after the prepend.Typical use case: when the user pastes or creates an object that does not yet appear in the current query (e.g. because the index has not been updated), drop it in temporarily so the user sees it immediately without a full refresh.Drop-in items are cleared automatically when the user navigates to a different page. Call dropItems([]) to remove them programmatically.Example :
Defaults to `true` so the newly dropped items are immediately visible.dropItems(items: T[], scrollTo: unknown): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| items | T[] | |
| scrollTo | unknown |
goToPage
Section titled “goToPage”Fetches and displays the given page of the current query result.Sets busy to true for the duration of the request. On success, updates the pagination state, clears all optimistic overrides (they are page-scoped), and replaces #items with the new page’s results.Also used internally by refresh() to reload the currently active page.
goToPage(page: number): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| page | number |
multiSelect
Section titled “multiSelect”Programmatically replaces the entire selection with the given indices.Only effective when multiselect is true. Out-of-range indices are silently discarded. The resulting selection is sorted ascending before being applied.Use this when the parent needs to restore a previously saved multi-selection state, e.g. after navigation or component re-initialization.
multiSelect(index: number[]): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| index | number[] |
onDragSelect
Section titled “onDragSelect”Handles the final committed drag-selection from DragSelectDirective.Called when the user releases the mouse after a drag-to-select gesture. Transfers DOM focus to the list (so keyboard navigation works immediately after) and emits the final selection via itemSelect.Called from the template via (dragSelect) on the drag-select host. Not intended for external callers.
onDragSelect(sel: number[]): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| sel | number[] |
onDragSelectChange
Section titled “onDragSelectChange”Handles intermediate drag-selection changes from DragSelectDirective.Fires continuously while the user is dragging across items. Updates the inner list’s multi-selection state in real time so items are highlighted as the drag progresses, and also emits dragSelectChange so the parent can show a live preview.Called from the template via (dragSelectChange) on the drag-select host. Not intended for external callers.
onDragSelectChange(sel: number[]): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| sel | number[] |
onItemClick
Section titled “onItemClick”Handles a single click on a list item.Forwards the click to the inner ListComponent with the correct Shift/Ctrl modifier flags so range- and toggle-selection work correctly. Also transfers DOM focus to the list host so subsequent keyboard navigation works without an additional Tab press.Called from the template via (click) on each item wrapper. Not intended for external callers — use select() instead.
onItemClick(idx: number, event: MouseEvent): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| idx | number | |
| event | MouseEvent |
onItemDoubleClick
Section titled “onItemDoubleClick”Handles a double-click on a list item.Emits the itemDoubleClick output with the item’s index. The parent can use this to trigger a secondary action (e.g. opening a detail panel or navigating to a route) that is distinct from the primary single-click selection.Called from the template via ClickDoubleDirective. Not intended for external callers.
onItemDoubleClick(idx: number, event: MouseEvent): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| idx | number | |
| event | MouseEvent |
refresh
Section titled “refresh”Re-executes the current query without changing the page or query parameters.If pagination is active, re-fetches the same page the user is currently on. If no pagination is active, re-runs the original query from scratch.Use this to reflect server-side changes (e.g. after a create/delete operation) without navigating away from the current view.
refresh(): voidrunTransformerAgain
Section titled “runTransformerAgain”Forces the transformer function to be re-applied to the current result set.Normally the transformer runs automatically whenever the underlying #items signal changes. Use this method when the transformer itself has external dependencies that changed (e.g. a locale or display-format setting) but the raw search result did not — triggering a re-evaluation by creating a new array reference for #items without fetching from the server again.
runTransformerAgain(): voidselect
Section titled “select”Selects the item at the given zero-based index.Delegates to the inner ListComponent. The preventChangeUntil guard and disableSelection state are respected. Clamps the index to the valid range.
select(index: number): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| index | number |
setActiveItem
Section titled “setActiveItem”Moves keyboard focus to the item at the given index and selects it.Combines focus management and selection in one call, and transfers DOM focus to the list host. Use this when the parent wants to programmatically drive both the visual focus indicator and the selection simultaneously.
setActiveItem(index: number): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| index | number |
trackItem
Section titled “trackItem”Resolves the tracking key for a result item in the @for loop.
trackItem(item: T, index: number): unknownArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| item | T | |
| index | number |
updateListItems
Section titled “updateListItems”Applies optimistic per-item overrides on top of the current query result.Each entry in the updates array patches the item at the given index with the provided value. The value type must match T — i.e. the shape produced by the transformer function, or SearchResultItem if no transformer is used.Overrides accumulate: calling this method multiple times merges the new entries with any previously applied ones. All overrides are automatically discarded when the user navigates to a different page (see goToPage()), since a fresh server response replaces the local data.Use case: apply instant visual feedback after a user action (rename, status change, etc.) without waiting for a full query refresh.
updateListItems(updates: literal type[]): voidArguments
Section titled “Arguments”| Name | Type | Description |
|---|---|---|
| updates | literal type[] |