Skip to content

Commit f5960d0

Browse files
atscottthePunderWoman
authored andcommitted
refactor(docs-infra): Use new APIs in search dialog (angular#57215)
This updates the search dialog component to use signal APIs PR Close angular#57215
1 parent 89f28b6 commit f5960d0

File tree

3 files changed

+54
-68
lines changed

3 files changed

+54
-68
lines changed

adev/shared-docs/components/search-dialog/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ ts_library(
4646
"//adev/shared-docs/services",
4747
"//adev/shared-docs/testing",
4848
"//packages/core",
49+
"//packages/core/testing",
4950
"//packages/platform-browser",
5051
"//packages/router",
52+
"//packages/router/testing",
5153
],
5254
)
5355

adev/shared-docs/components/search-dialog/search-dialog.component.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ describe('SearchDialog', () => {
5656

5757
fakeSearch.searchResults.and.returnValue(fakeSearchResults);
5858
fixture.detectChanges();
59-
fixture.componentInstance.ngAfterViewInit();
6059

6160
fakeWindow.dispatchEvent(
6261
new KeyboardEvent('keydown', {

adev/shared-docs/components/search-dialog/search-dialog.component.ts

Lines changed: 52 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@
77
*/
88

99
import {
10-
AfterViewInit,
1110
ChangeDetectionStrategy,
1211
Component,
13-
DestroyRef,
1412
ElementRef,
15-
EventEmitter,
16-
NgZone,
13+
Injector,
1714
OnDestroy,
18-
OnInit,
19-
Output,
20-
QueryList,
21-
ViewChild,
22-
ViewChildren,
15+
Signal,
16+
afterNextRender,
17+
effect,
2318
inject,
19+
output,
20+
viewChild,
21+
viewChildren,
2422
} from '@angular/core';
2523

2624
import {WINDOW} from '../../providers/index';
@@ -53,95 +51,82 @@ import {RelativeLink} from '../../pipes/relative-link.pipe';
5351
templateUrl: './search-dialog.component.html',
5452
styleUrls: ['./search-dialog.component.scss'],
5553
})
56-
export class SearchDialog implements OnInit, AfterViewInit, OnDestroy {
57-
@Output() onClose = new EventEmitter<void>();
58-
@ViewChild('searchDialog') dialog?: ElementRef<HTMLDialogElement>;
59-
@ViewChildren(SearchItem) items?: QueryList<SearchItem>;
54+
export class SearchDialog implements OnDestroy {
55+
onClose = output();
56+
dialog = viewChild.required('searchDialog', {read: ElementRef}) as Signal<
57+
ElementRef<HTMLDialogElement>
58+
>;
59+
items = viewChildren(SearchItem);
6060

61-
private readonly destroyRef = inject(DestroyRef);
62-
private readonly ngZone = inject(NgZone);
6361
private readonly search = inject(Search);
6462
private readonly relativeLink = new RelativeLink();
6563
private readonly router = inject(Router);
6664
private readonly window = inject(WINDOW);
67-
68-
private keyManager?: ActiveDescendantKeyManager<SearchItem>;
65+
private readonly injector = inject(Injector);
66+
private readonly keyManager = new ActiveDescendantKeyManager(
67+
this.items,
68+
this.injector,
69+
).withWrap();
6970

7071
searchQuery = this.search.searchQuery;
7172
searchResults = this.search.searchResults;
7273

73-
ngOnInit(): void {
74-
this.ngZone.runOutsideAngular(() => {
75-
fromEvent<KeyboardEvent>(this.window, 'keydown')
76-
.pipe(
77-
filter((_) => !!this.keyManager),
78-
takeUntilDestroyed(this.destroyRef),
79-
)
80-
.subscribe((event) => {
81-
// When user presses Enter we can navigate to currently selected item in the search result list.
82-
if (event.key === 'Enter') {
83-
this.navigateToTheActiveItem();
84-
} else {
85-
this.ngZone.run(() => {
86-
this.keyManager?.onKeydown(event);
87-
});
88-
}
89-
});
74+
constructor() {
75+
effect(() => {
76+
this.items();
77+
afterNextRender(
78+
{
79+
write: () => this.keyManager.setFirstItemActive(),
80+
},
81+
{injector: this.injector},
82+
);
9083
});
91-
}
92-
93-
ngAfterViewInit() {
94-
if (!this.dialog?.nativeElement.open) {
95-
this.dialog?.nativeElement.showModal?.();
96-
}
9784

98-
if (!this.items) {
99-
return;
100-
}
85+
this.keyManager.change.pipe(takeUntilDestroyed()).subscribe(() => {
86+
this.keyManager.activeItem?.scrollIntoView();
87+
});
10188

102-
this.keyManager = new ActiveDescendantKeyManager(this.items).withWrap();
103-
this.keyManager?.setFirstItemActive();
89+
afterNextRender({
90+
write: () => {
91+
if (!this.dialog().nativeElement.open) {
92+
this.dialog().nativeElement.showModal?.();
93+
}
94+
},
95+
});
10496

105-
this.updateActiveItemWhenResultsChanged();
106-
this.scrollToActiveItem();
97+
fromEvent<KeyboardEvent>(this.window, 'keydown')
98+
.pipe(takeUntilDestroyed())
99+
.subscribe((event) => {
100+
// When user presses Enter we can navigate to currently selected item in the search result list.
101+
if (event.key === 'Enter') {
102+
this.navigateToTheActiveItem();
103+
} else {
104+
this.keyManager.onKeydown(event);
105+
}
106+
});
107107
}
108108

109109
ngOnDestroy(): void {
110-
this.keyManager?.destroy();
110+
this.keyManager.destroy();
111111
}
112112

113113
closeSearchDialog() {
114-
this.dialog?.nativeElement.close();
115-
this.onClose.next();
114+
this.dialog().nativeElement.close();
115+
this.onClose.emit();
116116
}
117117

118118
updateSearchQuery(query: string) {
119119
this.search.updateSearchQuery(query);
120120
}
121121

122-
private updateActiveItemWhenResultsChanged(): void {
123-
this.items?.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
124-
// Change detection should be run before execute `setFirstItemActive`.
125-
Promise.resolve().then(() => {
126-
this.keyManager?.setFirstItemActive();
127-
});
128-
});
129-
}
130-
131122
private navigateToTheActiveItem(): void {
132-
const activeItemLink: string | undefined = this.keyManager?.activeItem?.item?.url;
123+
const activeItemLink: string | undefined = this.keyManager.activeItem?.item?.url;
133124

134125
if (!activeItemLink) {
135126
return;
136127
}
137128

138129
this.router.navigateByUrl(this.relativeLink.transform(activeItemLink));
139-
this.onClose.next();
140-
}
141-
142-
private scrollToActiveItem(): void {
143-
this.keyManager?.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
144-
this.keyManager?.activeItem?.scrollIntoView();
145-
});
130+
this.onClose.emit();
146131
}
147132
}

0 commit comments

Comments
 (0)