|
7 | 7 | */
|
8 | 8 |
|
9 | 9 | import {
|
10 |
| - AfterViewInit, |
11 | 10 | booleanAttribute,
|
12 | 11 | computed,
|
13 | 12 | contentChildren,
|
14 | 13 | Directive,
|
| 14 | + effect, |
15 | 15 | ElementRef,
|
16 | 16 | inject,
|
17 | 17 | input,
|
18 | 18 | model,
|
| 19 | + signal, |
19 | 20 | } from '@angular/core';
|
20 | 21 | import {ListboxPattern, OptionPattern} from '../ui-patterns';
|
21 | 22 | import {Directionality} from '@angular/cdk/bidi';
|
@@ -50,9 +51,10 @@ import {_IdGenerator} from '@angular/cdk/a11y';
|
50 | 51 | '[attr.aria-activedescendant]': 'pattern.activedescendant()',
|
51 | 52 | '(keydown)': 'pattern.onKeydown($event)',
|
52 | 53 | '(pointerdown)': 'pattern.onPointerdown($event)',
|
| 54 | + '(focusin)': 'onFocus()', |
53 | 55 | },
|
54 | 56 | })
|
55 |
| -export class CdkListbox<V> implements AfterViewInit { |
| 57 | +export class CdkListbox<V> { |
56 | 58 | /** The directionality (LTR / RTL) context for the application (or a subtree of it). */
|
57 | 59 | private readonly _directionality = inject(Directionality);
|
58 | 60 |
|
@@ -107,14 +109,27 @@ export class CdkListbox<V> implements AfterViewInit {
|
107 | 109 | textDirection: this.textDirection,
|
108 | 110 | });
|
109 | 111 |
|
110 |
| - ngAfterViewInit() { |
111 |
| - if (this.value().length) { |
112 |
| - // TODO(wagnermaciel): Write a test case specifically for this. |
113 |
| - const item = this.items().find(item => this.value().includes(item.value())); |
114 |
| - if (item) { |
115 |
| - this.activeIndex.set(item.index()); |
| 112 | + /** Whether the listbox has received focus yet. */ |
| 113 | + private touched = signal(false); |
| 114 | + |
| 115 | + /** Whether the options in the listbox have been initialized. */ |
| 116 | + private isViewInitialized = signal(false); |
| 117 | + |
| 118 | + constructor() { |
| 119 | + effect(() => { |
| 120 | + if (this.isViewInitialized() && !this.touched()) { |
| 121 | + const index = this.items().findIndex(i => this.value().includes(i.value())); |
| 122 | + this.activeIndex.set(Math.max(index, 0)); |
116 | 123 | }
|
117 |
| - } |
| 124 | + }); |
| 125 | + } |
| 126 | + |
| 127 | + ngAfterViewInit() { |
| 128 | + this.isViewInitialized.set(true); |
| 129 | + } |
| 130 | + |
| 131 | + onFocus() { |
| 132 | + this.touched.set(true); |
118 | 133 | }
|
119 | 134 | }
|
120 | 135 |
|
@@ -144,6 +159,7 @@ export class CdkOption<V> {
|
144 | 159 | /** A unique identifier for the option. */
|
145 | 160 | protected id = computed(() => this._generatedId);
|
146 | 161 |
|
| 162 | + /** The value of the option. */ |
147 | 163 | protected value = input.required<V>();
|
148 | 164 |
|
149 | 165 | // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not
|
|
0 commit comments