我有一个简单的组件,它使用在搜索框中输入的值来执行搜索。我找到了两种不同的方法来编码,它们都有效。
方法 1 使用 RxJS 中的
fromEvent
并设置一个可观察对象,以使用对输入元素的 @ViewChild
引用来捕获输入字段值的变化。
方法 2 使用
keyup
事件捕获输入字段值更改,并将新值提供给 RxJS Subject
。
我在 Stackoverflow 和其他网站上找到的大多数示例都使用 @ViewChild 来处理此类场景。是否有任何理由使用一种方法而不是另一种方法,或者这是个人选择的问题?
app.component.html
<input type="text" #search placeholder="Search" />
<li *ngFor="let state of states$ | async">
{{ state.text }}
</li>
app.component.ts
export class AppComponent implements OnInit {
@ViewChild('search', { static: true }) search: ElementRef;
states$: Observable<any[]>;
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.states$ = fromEvent(this.search.nativeElement, 'input').pipe(
map((event: any) => event.target.value),
debounceTime(500),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.getData(searchText))
);
}
}
app.component.html
<input
type="text"
(keyup)="searchStringChange(getValue($event))"
placeholder="Search"
/>
<li *ngFor="let state of states$ | async">
{{ state.text }}
</li>
app.component.ts
export class AppComponent implements OnInit {
states$: Observable<any[]>;
private searchText$ = new Subject<string>();
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.states$ = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
tap({ next: (searchText: string) => console.log(searchText) }),
switchMap((searchText: string) => this.dataService.getData(searchText))
);
}
searchStringChange(userInput: string) {
this.searchText$.next(userInput);
}
getValue(event: Event): string {
return (event.target as HTMLInputElement).value;
}
}
我尽可能避免使用@ViewChild。原因是当组件不必处理模板问题时,代码会更简单。当你引入模板关注点时,你需要担心目标元素当前是否在 DOM 中(它可能被 ngIf 隐藏),并且你需要担心在正确的角度生命周期钩子中访问它。
当使用“主题方法”时,组件只需要关心数据,模板可以简单地根据相关事件推送数据。
注意,在你的“方法2”中,没有必要使用
ngOnInit
,你可以简单地“在类上”初始化你的可观察对象:
export class AppComponent {
private searchText$ = new Subject<string>();
states$: Observable<any[]> = this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
tap(searchText => console.log(searchText)),
switchMap(searchText => this.dataService.getData(searchText))
);
constructor(private dataService: DataService) {}
searchStringChange(userInput: string) {
this.searchText$.next(userInput);
}
getValue(event: Event): string {
return (event.target as HTMLInputElement).value;
}
}
还有第三种方法可以处理这个问题,因为您正在处理表单输入。您可以使用 Angular 的反应形式。 FormControl 对象提供了一个方便的
valueChanges
可观察对象,每当输入值发生变化时就会发出:
export class AppComponent {
searchText = new FormControl<string>('');
states$ = this.searchText.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
tap(searchText => console.log(searchText)),
switchMap(searchText => this.dataService.getData(searchText))
);
constructor(private dataService: DataService) {}
}
<input type="text" [formControl]="searchText" placeholder="Search" />
<li *ngFor="let state of states$ | async">
{{ state.text }}
</li>
这是一个有效的 StackBlitz 演示。