Skip to content

Commit c1bf590

Browse files
committed
feat(cdk-experimental/combobox): set up lazy loading
1 parent 4e37144 commit c1bf590

File tree

8 files changed

+71
-19
lines changed

8 files changed

+71
-19
lines changed

src/cdk-experimental/combobox/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ ng_project(
1010
),
1111
deps = [
1212
"//:node_modules/@angular/core",
13+
"//src/cdk-experimental/deferred-content",
1314
],
1415
)

src/cdk-experimental/combobox/combobox.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,50 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Directive, input} from '@angular/core';
9+
import {contentChild, Directive, inject} from '@angular/core';
10+
import {DeferredContent, DeferredContentAware} from '@angular/cdk-experimental/deferred-content';
11+
12+
@Directive({
13+
selector: '[cdkCombobox]',
14+
exportAs: 'cdkCombobox',
15+
hostDirectives: [
16+
{
17+
directive: DeferredContentAware,
18+
inputs: ['preserveContent'],
19+
},
20+
],
21+
})
22+
export class CdkCombobox {
23+
/** The DeferredContentAware host directive. */
24+
private readonly _deferredContentAware = inject(DeferredContentAware, {optional: true});
25+
26+
/** The combobox popup. */
27+
readonly popup = contentChild(CdkComboboxPopup);
28+
29+
constructor() {
30+
this._deferredContentAware?.contentVisible.set(true);
31+
}
32+
}
1033

1134
@Directive({
1235
selector: 'input[cdkComboboxInput]',
1336
exportAs: 'cdkComboboxInput',
1437
host: {'role': 'combobox'},
1538
})
16-
export class CdkComboboxInput {
17-
readonly popup = input.required<CdkComboboxPopup>();
18-
}
39+
export class CdkComboboxInput {}
40+
41+
@Directive({
42+
selector: 'ng-template[cdkComboboxPopupContent]',
43+
exportAs: 'cdkComboboxPopupContent',
44+
hostDirectives: [DeferredContent],
45+
})
46+
export class CdkComboboxPopupContent {}
1947

2048
@Directive({
2149
selector: '[cdkComboboxPopup]',
2250
exportAs: 'cdkComboboxPopup',
2351
})
24-
export class CdkComboboxPopup {}
52+
export class CdkComboboxPopup {
53+
/** The combobox that the popup belongs to. */
54+
readonly combobox = inject(CdkCombobox, {optional: true});
55+
}

src/cdk-experimental/combobox/public-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
export {CdkComboboxInput, CdkComboboxPopup} from './combobox';
9+
export {CdkCombobox, CdkComboboxInput, CdkComboboxPopup, CdkComboboxPopupContent} from './combobox';

src/cdk-experimental/listbox/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ng_project(
1010
),
1111
deps = [
1212
"//:node_modules/@angular/core",
13+
"//src/cdk-experimental/combobox",
1314
"//src/cdk-experimental/ui-patterns",
1415
"//src/cdk/a11y",
1516
"//src/cdk/bidi",

src/cdk-experimental/listbox/listbox.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {ListboxPattern, OptionPattern} from '../ui-patterns';
2222
import {Directionality} from '@angular/cdk/bidi';
2323
import {toSignal} from '@angular/core/rxjs-interop';
2424
import {_IdGenerator} from '@angular/cdk/a11y';
25+
import {CdkComboboxPopup} from '../combobox';
2526

2627
/**
2728
* A listbox container.
@@ -53,8 +54,11 @@ import {_IdGenerator} from '@angular/cdk/a11y';
5354
'(pointerdown)': 'pattern.onPointerdown($event)',
5455
'(focusin)': 'onFocus()',
5556
},
57+
hostDirectives: [{directive: CdkComboboxPopup}],
5658
})
5759
export class CdkListbox<V> {
60+
private readonly _popup = inject(CdkComboboxPopup, {optional: true});
61+
5862
/** A reference to the listbox element. */
5963
private readonly _elementRef = inject(ElementRef);
6064

@@ -109,6 +113,7 @@ export class CdkListbox<V> {
109113
activeItem: signal(undefined),
110114
textDirection: this.textDirection,
111115
element: () => this._elementRef.nativeElement,
116+
isComboboxPopup: () => !!this._popup?.combobox,
112117
});
113118

114119
/** Whether the listbox has received focus yet. */

src/cdk-experimental/ui-patterns/listbox/listbox.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import {List, ListInputs} from '../behaviors/list/list';
1515
/** Represents the required inputs for a listbox. */
1616
export type ListboxInputs<V> = ListInputs<OptionPattern<V>, V> & {
1717
readonly: SignalLike<boolean>;
18+
19+
/** Whether the listbox is in a combobox popup. */
20+
isComboboxPopup: SignalLike<boolean>;
1821
};
1922

2023
/** Controls the state of a listbox. */
@@ -215,13 +218,13 @@ export class ListboxPattern<V> {
215218

216219
/** Handles keydown events for the listbox. */
217220
onKeydown(event: KeyboardEvent) {
218-
if (!this.disabled()) {
221+
if (!this.disabled() && !this.inputs.isComboboxPopup()) {
219222
this.keydown().handle(event);
220223
}
221224
}
222225

223226
onPointerdown(event: PointerEvent) {
224-
if (!this.disabled()) {
227+
if (!this.disabled() && !this.inputs.isComboboxPopup()) {
225228
this.pointerdown().handle(event);
226229
}
227230
}
@@ -237,6 +240,10 @@ export class ListboxPattern<V> {
237240
* is called.
238241
*/
239242
setDefaultState() {
243+
if (this.inputs.isComboboxPopup()) {
244+
return;
245+
}
246+
240247
let firstItem: OptionPattern<V> | null = null;
241248

242249
for (const item of this.inputs.items()) {

src/dev-app/cdk-experimental-combobox/cdk-combobox-demo.html

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
<div class="example-combobox-container">
1+
<div cdkCombobox class="example-combobox-container">
22
<div class="example-combobox-input-container">
33
<span class="material-symbols-outlined example-icon example-search-icon">search</span>
4-
<input
5-
cdkComboboxInput
6-
class="example-combobox-input"
7-
[popup]="popup"
8-
placeholder="Search..."
9-
/>
4+
<input cdkComboboxInput class="example-combobox-input" placeholder="Search..." />
105
</div>
116

12-
<div cdkComboboxPopup #popup="cdkComboboxPopup">
7+
<ng-template cdkComboboxPopupContent>
138
<div cdkListbox class="example-listbox" [value]="['Apple']">
149
@for (fruit of fruits; track fruit) {
1510
<div
@@ -27,5 +22,5 @@
2722
</div>
2823
}
2924
</div>
30-
</div>
25+
</ng-template>
3126
</div>

src/dev-app/cdk-experimental-combobox/cdk-combobox-demo.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,26 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {CdkComboboxInput, CdkComboboxPopup} from '@angular/cdk-experimental/combobox';
9+
import {
10+
CdkCombobox,
11+
CdkComboboxInput,
12+
CdkComboboxPopup,
13+
CdkComboboxPopupContent,
14+
} from '@angular/cdk-experimental/combobox';
1015
import {CdkListbox, CdkOption} from '@angular/cdk-experimental/listbox';
1116
import {ChangeDetectionStrategy, Component} from '@angular/core';
1217

1318
@Component({
1419
templateUrl: 'cdk-combobox-demo.html',
1520
styleUrl: 'cdk-combobox-demo.css',
16-
imports: [CdkComboboxInput, CdkComboboxPopup, CdkListbox, CdkOption],
21+
imports: [
22+
CdkCombobox,
23+
CdkComboboxInput,
24+
CdkComboboxPopup,
25+
CdkComboboxPopupContent,
26+
CdkListbox,
27+
CdkOption,
28+
],
1729
changeDetection: ChangeDetectionStrategy.OnPush,
1830
})
1931
export class CdkComboboxDemo {

0 commit comments

Comments
 (0)