typescript 如何使用表单输入过滤Observable数组中的对象?

but5z9lq  于 2023-01-06  发布在  TypeScript
关注(0)|答案(1)|浏览(146)

如何使用这些标志上方的表单输入来过滤下方的标志?
https://stackblitz.com/edit/angular-ivy-s2ujmr?file=src/app/country-card/country-card.component.html
我想我可以像这样在管道中使用filter函数:

searchFilterCountries(searchTerm: string){
    this.countries$.pipe(filter((country: any) => country.name.common.toLowerCase().includes(searchTerm.toLowerCase())))
  }

并将输入放入html模板中,如下所示:

<input type="text" class="form-control" (input)="searchFilterCountries($event.target.value)"/>

以便每次有输入时过滤器函数都会触发,从而缩小显示的国家列表。
但是这个方法行不通。如果这个方法行得通,请解释我做错了什么。
经过几天的谷歌搜索和阅读,我想出了这样的帖子

主页.组件.html

<div>
  <input type="text" [formControl]="myControl" />
  <app-country-card *ngFor="let country of countries$ | async" [country]="country"></app-country-card>
</div>

主页.组件.ts

export class HomeComponent {
  allCountries: Country[] = [];
  countries$!: Observable<Country[]>;
  myControl = new FormControl('');
  constructor(private apiService: ApiService) {}

  ngOnInit() {
    this.apiService
      .getAllCountries().subscribe(countries => this.allCountries = countries);

    this.countries$ = this.myControl.valueChanges.pipe(
      startWith(''),
      map(searchTerm => this._filter(searchTerm))
    );
  }

  private _filter(value: string | null): Country[] {
    if (value === null) {
      return this.allCountries;
    }
    const filterValue = value?.toLowerCase();

    return this.allCountries.filter(country => country.name.common.toLowerCase().includes(filterValue));
  }
}

但这也不起作用。页面保持空白,没有标志加载/呈现,直到输入的东西。我需要所有的结果呈现,然后能够过滤他们。
我是Angular的新手,这比我预期的要困难得多。我花了几天时间试图让它工作,但不能再花时间了。我迫切需要帮助。有人能告诉我我做错了什么,以及如何解决这个问题吗?

x3naxklr

x3naxklr1#

在第一段代码中,你创建了一个管道(一个管道化的可观察对象),但是你对它做了任何事情。它没有被返回,你也没有订阅它。你必须将.subscribe()绑定到Observable,否则它什么也不会做。
另外,如果你觉得有必要声明一个参数为any,就像你在this.countries$.pipe(filter((country: any) => ...中做的那样,你通常会做错什么。请看一下filter的文档。它不是过滤数组的元素,就像[].filter(...)一样,也不是你使用它的时候。
你的第二种方法更好用。你的错误在于,你只在搜索词改变时过滤。如果数据被加载,你 * 不 * 再次过滤。你需要对这两个事件做出React:数据加载和搜索项更改。您可以使用combineLatest -operator

// requests & emits all countries
const loadCountries$ = this.apiService.getAllCountries().pipe(
  tap((countries) => this.allCountries = countries)
);

// emits the search term when the user types, always starts with ''
const searchTerm$ = this.myControl.valueChanges.pipe(
  startWith('')
);

// whenever either loadCountries$ or searchTerm$ emits
// (but only after each emitted at least once)
// applies a filter-function and emits the filtered countries.
this.countries$ = combineLatest(loadCountries$, searchTerm$).pipe(
  map(([countries, searchTerm]) => this.filter(countries, searchTerm)),
);

注意,在本例中,this.filter被更改为接受两个参数,过滤国家 * 和搜索项 *。您最好保留您的版本并使用成员this.allCountries

相关问题