Skip to content

Commit c2019dc

Browse files
committed
fixup! fix(cdk-experimental/listbox): initial listbox focus state
1 parent 501c347 commit c2019dc

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

src/cdk-experimental/listbox/listbox.ts

+25-9
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
*/
88

99
import {
10-
AfterViewInit,
1110
booleanAttribute,
1211
computed,
1312
contentChildren,
1413
Directive,
14+
effect,
1515
ElementRef,
1616
inject,
1717
input,
1818
model,
19+
signal,
1920
} from '@angular/core';
2021
import {ListboxPattern, OptionPattern} from '../ui-patterns';
2122
import {Directionality} from '@angular/cdk/bidi';
@@ -50,9 +51,10 @@ import {_IdGenerator} from '@angular/cdk/a11y';
5051
'[attr.aria-activedescendant]': 'pattern.activedescendant()',
5152
'(keydown)': 'pattern.onKeydown($event)',
5253
'(pointerdown)': 'pattern.onPointerdown($event)',
54+
'(focusin)': 'onFocus()',
5355
},
5456
})
55-
export class CdkListbox<V> implements AfterViewInit {
57+
export class CdkListbox<V> {
5658
/** The directionality (LTR / RTL) context for the application (or a subtree of it). */
5759
private readonly _directionality = inject(Directionality);
5860

@@ -107,14 +109,27 @@ export class CdkListbox<V> implements AfterViewInit {
107109
textDirection: this.textDirection,
108110
});
109111

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));
116123
}
117-
}
124+
});
125+
}
126+
127+
ngAfterViewInit() {
128+
this.isViewInitialized.set(true);
129+
}
130+
131+
onFocus() {
132+
this.touched.set(true);
118133
}
119134
}
120135

@@ -144,6 +159,7 @@ export class CdkOption<V> {
144159
/** A unique identifier for the option. */
145160
protected id = computed(() => this._generatedId);
146161

162+
/** The value of the option. */
147163
protected value = input.required<V>();
148164

149165
// TODO(wagnermaciel): See if we want to change how we handle this since textContent is not

src/components-examples/cdk-experimental/listbox/cdk-listbox/cdk-listbox-example.html

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
<mat-checkbox [formControl]="readonly">Readonly</mat-checkbox>
66
<mat-checkbox [formControl]="skipDisabled">Skip Disabled</mat-checkbox>
77

8+
<mat-form-field subscriptSizing="dynamic" appearance="outline">
9+
<mat-label>Selection</mat-label>
10+
<mat-select [(value)]="selection" multiple>
11+
@for (fruit of fruits; track fruit) {
12+
<mat-option [value]="fruit">{{fruit}}</mat-option>
13+
}
14+
</mat-select>
15+
</mat-form-field>
16+
817
<mat-form-field subscriptSizing="dynamic" appearance="outline">
918
<mat-label>Orientation</mat-label>
1019
<mat-select [(value)]="orientation">
@@ -34,6 +43,7 @@
3443
<ul
3544
cdkListbox
3645
[wrap]="wrap.value"
46+
[value]="selection"
3747
[multi]="multi.value"
3848
[readonly]="readonly.value"
3949
[disabled]="disabled.value"

src/components-examples/cdk-experimental/listbox/cdk-listbox/cdk-listbox-example.ts

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export class CdkListboxExample {
2727
focusMode: 'roving' | 'activedescendant' = 'roving';
2828
selectionMode: 'explicit' | 'follow' = 'explicit';
2929

30+
selection = [];
31+
3032
wrap = new FormControl(true, {nonNullable: true});
3133
multi = new FormControl(false, {nonNullable: true});
3234
disabled = new FormControl(false, {nonNullable: true});

0 commit comments

Comments
 (0)