8000 docs(docs-infra): preselect search text on re-open (#61129) · angular/angular@6e2fa1d · GitHub
[go: up one dir, main page]

Skip to content

Commit 6e2fa1d

Browse files
JeanMechealxhub
authored andcommitted
docs(docs-infra): preselect search text on re-open (#61129)
PR Close #61129
1 parent f5f6ead commit 6e2fa1d

File tree

6 files changed

+38
-15
lines changed

6 files changed

+38
-15
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<docs-text-field
44
[autofocus]="true"
55
[hideIcon]="true"
6-
[(ngModel)]="searchQuery"
6+
[formControl]="searchControl"
77
[resetLabel]="'Clear the search'"
88
class="docs-search-input"
99
placeholder="Search docs"

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {ClickOutside} from '../../directives/index';
2525
import {Search} from '../../services/index';
2626

2727
import {TextField} from '../text-field/text-field.component';
28-
import {FormsModule} from '@angular/forms';
28+
import {FormControl, ReactiveFormsModule} from '@angular/forms';
2929
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
3030
import {SearchItem} from '../../directives/search-item/search-item.directive';
3131
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
@@ -40,7 +40,7 @@ import {RelativeLink} from '../../pipes/relative-link.pipe';
4040
imports: [
4141
ClickOutside,
4242
TextField,
43-
FormsModule,
43+
ReactiveFormsModule,
4444
SearchItem,
4545
AlgoliaIcon,
4646
RelativeLink,
@@ -53,6 +53,7 @@ export class SearchDialog implements OnDestroy {
5353
onClose = output();
5454
dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
5555
items = viewChildren(SearchItem);
56+
textField = viewChild(TextField);
5657

5758
private readonly search = inject(Search);
5859
private readonly relativeLink = new RelativeLink();
@@ -67,7 +68,18 @@ export class SearchDialog implements OnDestroy {
6768
searchQuery = this.search.searchQuery;
6869
searchResults = this.search.searchResults;
6970

71+
// We use a FormControl instead of relying on NgModel+signal to avoid
72+
// the issue https://github.com/angular/angular/issues/13568
73+
// TODO: Use signal forms when available
74+
searchControl = new FormControl(this.searchQuery(), {nonNullable: true});
75+
7076
constructor() {
77+
this.searchControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
78+
this.searchQuery.set(value);
79+
});
80+
81+
// Thinkig about refactoring this to a single afterRenderEffect ?
82+
// Answer: It won't have the same behavior
7183
effect(() => {
7284
this.items();
7385
afterNextRender(
@@ -87,6 +99,9 @@ export class SearchDialog implements OnDestroy {
8799
if (!this.dialog().nativeElement.open) {
88100
this.dialog().nativeElement.showModal?.();
89101
}
102+
// We want to select the pre-existing text on opening
103+
// In order to change the search input with minimal user interaction.
104+
this.textField()?.input().nativeElement.select();
90105
},
91106
});
92107

adev/shared-docs/components/text-field/text-field.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
type="text"
77
[attr.placeholder]="placeholder()"
88
[attr.name]="name()"
9-
[ngModel]="value()"
10-
(ngModelChange)="setValue($event)"
9+
[value]="value()"
10+
(input)="setValue(inputRef.value)"
1111
class="docs-text-field"
1212
/>
1313

adev/shared-docs/components/text-field/text-field.component.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,13 @@ describe('TextField', () => {
2828
it('should create', () => {
2929
expect(component).toBeTruthy();
3030
});
31+
32+
it('should update DOM when setting the value via the CVA', () => {
33+
component.setValue('test');
34+
fixture.detectChanges();
35+
36+
expect(fixture.nativeElement.querySelector('input').value).toBe('test');
37+
// If we were using ngModel instead of the value binding, we would get an empty string
38+
// because of https://github.com/angular/angular/issues/13568
39+
});
3140
});

adev/shared-docs/directives/search-item/search-item.directive.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {SearchResultItem} from '../../interfaces';
1717
},
1818
})
1919
export class SearchItem implements Highlightable {
20+
// Those inputs are required by the Highlightable interface
21+
// We can't migrate them to signals yet
2022
@Input() item?: SearchResultItem;
2123
@Input() disabled = false;
2224

adev/src/app/main.component.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,12 @@ export default class MainComponent {
2222
search = model<string | undefined>('');
2323

2424
constructor() {
25-
effect(
26-
() => {
27-
const search = this.search();
28-
if (search !== undefined) {
29-
this.displaySearchDialog.set(true);
30-
this.searchService.searchQuery.set(search);
31-
}
32-
},
33-
{allowSignalWrites: true},
34-
);
25+
effect(() => {
26+
const search = this.search();
27+
if (search !== undefined) {
28+
this.displaySearchDialog.set(true);
29+
this.searchService.searchQuery.set(search);
30+
}
31+
});
3532
}
3633
}

0 commit comments

Comments
 (0)
0