使用RxJS fromEvent和@ViewChild与keyup事件和RxJS主题进行输入字段值更改

问题描述 投票:0回答:1

我有一个简单的组件,它使用在搜索框中输入的值来执行搜索。我找到了两种不同的方法来编码,它们都有效。

方法 1 使用 RxJS 中的

fromEvent
并设置一个可观察对象,以使用对输入元素的
@ViewChild
引用来捕获输入字段值的变化。

方法 2 使用

keyup
事件捕获输入字段值更改,并将新值提供给 RxJS
Subject

我在 Stackoverflow 和其他网站上找到的大多数示例都使用 @ViewChild 来处理此类场景。是否有任何理由使用一种方法而不是另一种方法,或者这是个人选择的问题?

方法1

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))
    );
  }
}

方法2

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;
  }
}
javascript angular typescript rxjs observable
1个回答
0
投票

我尽可能避免使用@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 演示。

© www.soinside.com 2019 - 2024. All rights reserved.