|
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