如何在值更改之前实例化对象数组的Observable?

时间:2019-05-07 17:58:27

标签: angular rxjs angular-material observable

我正在遵循Autocomplete Angular Material documentation(v5设置单独的控件和显示值),但是在加载数据时遇到了一些问题。

我遇到的问题是,直到用户开始键入后,我的代码中的filteredOptions才会填充。在用户开始输入之前,我需要显示该列表。我相信这是因为他们正在使用valueChanges,但是我不太确定如何使这段代码适合我的情况。我需要此管道和地图功能,但是我需要在用户更改Mat Autocomplete值之前而不是之后更改列表。

从文档链接中获取的代码或多或少已映射到自己的代码中

<form class="example-form">
  <mat-form-field class="example-full-width">
    <input type="text" placeholder="Assignee" aria-label="Assignee" matInput [formControl]="myControl" [matAutocomplete]="auto">
    <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
      <mat-option *ngFor="let option of filteredOptions | async" [value]="option">
        {{ option.name }}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
</form>
filteredOptions: Observable<User[]>;

  ngOnInit() {
    this.filteredOptions = this.myControl.valueChanges
      .pipe(
        startWith<string | User>(''),
        map(value => typeof value === 'string' ? value : value.name),
        map(name => name ? this.filter(name) : this.categoryList.slice())
      );
  }

  filter(name: string): User[] {
    return this.categoryList.filter(option =>
      option.name.toLowerCase().indexOf(name.toLowerCase()) === 0);
  }

  displayFn(user?: User): string | undefined {
    return user ? user.name : undefined;
  }
this.categoryList = Object.entries(data.category).map(([key, value]) => ({ key, value }));

我当时想我应该使用某种订阅方式,但是我不知道将其用于管道和地图的语法。

2 个答案:

答案 0 :(得分:0)

我相信您要做的就是startWith表单的值:

  ngOnInit() {
    this.filteredOptions = this.myControl.valueChanges
      .pipe(
        startWith(this.myControl.value as string), // typing the control's value
        map(name => name ? this.filter(name) : this.categoryList.slice())
      );
  }

请注意,在运算符内部使用class方法有点反模式。通常,在使用Observable模式时保持事物纯净非常重要-尤其是对于更复杂的逻辑。

要解决此问题,您可能希望将categoryList设为可观察对象,并将filter设为纯函数(将其带到组件外部,并为其提供另一个参数,以便您可以通过在categoryList中。

function filter(name: string, categoryList: User[]): User[] {
  categoryList.filter(option =>
      option.name.toLowerCase().indexOf(name.toLowerCase()) === 0);
}

然后您可以这样做:

  ngOnInit() {
    this.filteredOptions = combineLatest(
      this.myControl.valueChanges.pipe(startWith(this.myControl.value as string)),
      this.categoryList
    ).pipe(
      map(([searchTerm, categoryList]) =>
        searchTerm ? filter(searchTerm, categoryList) : [ ...categoryList ])
    );
  }

答案 1 :(得分:0)

简直不敢这么简单,但是这个答案帮助解决了所有问题。我要做的就是将代码移到ngOnInit之外。 how to show autocomplete options on focus

我的filteredOptions没有等待API数据通过,因为我已经将其放入ngOnInit中。将其移到api调用的订阅中后,一切运行顺利。