mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
docs(docs-infra): preselect search text on re-open (#61129)
PR Close #61129
This commit is contained in:
parent
223ca9f983
commit
d1501bce5c
6 changed files with 38 additions and 15 deletions
|
|
@ -3,7 +3,7 @@
|
|||
<docs-text-field
|
||||
[autofocus]="true"
|
||||
[hideIcon]="true"
|
||||
[(ngModel)]="searchQuery"
|
||||
[formControl]="searchControl"
|
||||
[resetLabel]="'Clear the search'"
|
||||
class="docs-search-input"
|
||||
placeholder="Search docs"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {ClickOutside} from '../../directives/index';
|
|||
import {Search} from '../../services/index';
|
||||
|
||||
import {TextField} from '../text-field/text-field.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
||||
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
|
||||
import {SearchItem} from '../../directives/search-item/search-item.directive';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
|
|
@ -40,7 +40,7 @@ import {RelativeLink} from '../../pipes/relative-link.pipe';
|
|||
imports: [
|
||||
ClickOutside,
|
||||
TextField,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
SearchItem,
|
||||
AlgoliaIcon,
|
||||
RelativeLink,
|
||||
|
|
@ -53,6 +53,7 @@ export class SearchDialog implements OnDestroy {
|
|||
onClose = output();
|
||||
dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
|
||||
items = viewChildren(SearchItem);
|
||||
textField = viewChild(TextField);
|
||||
|
||||
private readonly search = inject(Search);
|
||||
private readonly relativeLink = new RelativeLink();
|
||||
|
|
@ -67,7 +68,18 @@ export class SearchDialog implements OnDestroy {
|
|||
searchQuery = this.search.searchQuery;
|
||||
searchResults = this.search.searchResults;
|
||||
|
||||
// We use a FormControl instead of relying on NgModel+signal to avoid
|
||||
// the issue https://github.com/angular/angular/issues/13568
|
||||
// TODO: Use signal forms when available
|
||||
searchControl = new FormControl(this.searchQuery(), {nonNullable: true});
|
||||
|
||||
constructor() {
|
||||
this.searchControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.searchQuery.set(value);
|
||||
});
|
||||
|
||||
// Thinkig about refactoring this to a single afterRenderEffect ?
|
||||
// Answer: It won't have the same behavior
|
||||
effect(() => {
|
||||
this.items();
|
||||
afterNextRender(
|
||||
|
|
@ -87,6 +99,9 @@ export class SearchDialog implements OnDestroy {
|
|||
if (!this.dialog().nativeElement.open) {
|
||||
this.dialog().nativeElement.showModal?.();
|
||||
}
|
||||
// We want to select the pre-existing text on opening
|
||||
// In order to change the search input with minimal user interaction.
|
||||
this.textField()?.input().nativeElement.select();
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
type="text"
|
||||
[attr.placeholder]="placeholder()"
|
||||
[attr.name]="name()"
|
||||
[ngModel]="value()"
|
||||
(ngModelChange)="setValue($event)"
|
||||
[value]="value()"
|
||||
(input)="setValue(inputRef.value)"
|
||||
class="docs-text-field"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,13 @@ describe('TextField', () => {
|
|||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update DOM when setting the value via the CVA', () => {
|
||||
component.setValue('test');
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('input').value).toBe('test');
|
||||
// If we were using ngModel instead of the value binding, we would get an empty string
|
||||
// because of https://github.com/angular/angular/issues/13568
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import {SearchResultItem} from '../../interfaces';
|
|||
},
|
||||
})
|
||||
export class SearchItem implements Highlightable {
|
||||
// Those inputs are required by the Highlightable interface
|
||||
// We can't migrate them to signals yet
|
||||
@Input() item?: SearchResultItem;
|
||||
@Input() disabled = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,15 +22,12 @@ export default class MainComponent {
|
|||
search = model<string | undefined>('');
|
||||
|
||||
constructor() {
|
||||
effect(
|
||||
() => {
|
||||
const search = this.search();
|
||||
if (search !== undefined) {
|
||||
this.displaySearchDialog.set(true);
|
||||
this.searchService.searchQuery.set(search);
|
||||
}
|
||||
},
|
||||
{allowSignalWrites: true},
|
||||
);
|
||||
effect(() => {
|
||||
const search = this.search();
|
||||
if (search !== undefined) {
|
||||
this.displaySearchDialog.set(true);
|
||||
this.searchService.searchQuery.set(search);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue