使用 formArray 时出现 Mat-AutoComplete 错误

Posted

技术标签:

【中文标题】使用 formArray 时出现 Mat-AutoComplete 错误【英文标题】:Mat-AutoComplete error when using formArray 【发布时间】:2021-09-11 03:12:34 【问题描述】:

我添加了一个表单数组来处理多行。为了使它与索引一起工作,我必须将我的定义从:shoppingCartList Observable<any[]>; 更改为 shoppingCartList: Observable<any[]>[] = [];,但是当我这样做时,它会在我的过滤器函数中抛出一个错误,即 missing the following properties from type 'Observable<any[]>[]': length, pop, push, concat。看起来是因为我正在调用服务来过滤列表。实现这一点的正确方法是什么: .HTML

<mat-autocomplete #auto="matAutocomplete" [displayWith]="entry">
       <mat-option *ngFor="let case of shoppingCartList[i] | async" [value]="case">
            title
         </mat-option>
 </mat-autocomplete>

.TS

    shoppingCartList: Observable<any[]>[] = [];
            
             this.shoppingCartList[index] = arrayControl.at(index).get('name').valueChanges //ERROR: (property) DraftformComponent.filteredPrimaryCaseSerial: Observable<any[]>[]
    Type 'Subscription' is missing the following properties from type 'Observable<any[]>

                .pipe(debounceTime(this.debounceTime))
                  .subscribe(
                    (val) => 
                        this.filteredList= this.getFilteredlist(val); //ERROR: (property) DraftformComponent.filteredPrimaryCaseSerial: Observable<any[]>[]
    Type 'Observable<any[]>' is missing the following properties from type 'Observable<any[]>[]
                      
                  );
        
         public getFilteredList(val: string): Observable<any[]> 
            return this.myService.getListByValue(val);
          

【问题讨论】:

我不知道到底想做什么。您是否有自动完成组件,并且当字段更改时,您希望填充过滤选项以显示服务数据? 是的,没错,但是因为它在表单数组中,所以它变得很棘手。我基于这个例子:stackblitz.com/edit/… 我认为,如果您稍微重构一下代码,您正在尝试做的事情会容易得多。您可以尝试创建您的设置的堆栈闪电战吗?我会做到这一点,这样您就没有任何可观察到的要传递给自动完成功能。处理所有数据,然后在组件中为处理后的数据设置一个变量,然后在 *ngFor 中使用该变量。我认为你应该从那个开始 听起来您正在使用服务来过滤数组。我假设你正在做一个自动完成,从服务器获得接下来的几个建议,对吗?你不应该需要一个 observable 的数组。看看这个问题的第二个答案:***.com/questions/57852645/… 是的,这是正确的@ChadK,如果有意义的话,我必须添加一个数组才能跟踪 formArray 中多行的用户数据。我是基于this 示例 【参考方案1】:

首先,您看到错误的原因是您输入列表的方式。

Observable&lt;any[]&gt;[] = [];

您已经在这里告诉编译器,您的购物车列表的类型是由多个可观察对象组成的数组。

所以,错误 missing the following properties from type 'Observable&lt;any[]&gt;[]': length, pop, push, concat 只是告诉您,您所说的 getFilteredList 将返回的内容实际上并不是函数期望返回的——它期望返回一个 可观察的数组 em>(任何类型)。

这与使用服务过滤列表无关。当您提到在这种情况下使用表单数组来解释多行时,我也有点不确定您的意思。

考虑到这一点 - 根据您的问题,这就是我认为您的目标。

  /**
   * Define a form which contains your FormControl you wish
   * to use for your autocomplete.
   */

  form = new FormGroup(
    shoppingListSearch: new FormControl()
  );

像这样访问它:

  get shoppingListSearch(): FormControl 
    return this.form.get('shoppingListSearch') as FormControl;
  

FormControls 将它们的值更改公开为可观察的,方便地称为valueChanges。您的尝试已经走在正确的轨道上!

我会使用 Angular 的模板,而不是手动订阅 observables。它在销毁组件时为您管理订阅的整理。如果您像上面那样手动订阅 observables,并且不取消订阅,您将留下订阅,导致内存泄漏。

像这样定义一个可观察对象:

  filteredList$: Observable<
    ShoppingListItem[]
  > = this.shoppingListSearch.valueChanges.pipe(
    debounceTime(1000),
    // Use a switchMap here to subscribe to the inner observable.
    // This is assuming your filtering needs to make a HTTP request.
    // switchMap will maintain one inner subscription, so should you 
    // make another request while one is in flight, the in flight 
    // request will be cancelled and a new one made with your new
    // search term.  
    switchMap((searchTerm: string) =>
      // this can be whatever filtering logic you want I guess.
      // To reiterate, I used a switchMap above as getFilteredList
      // returns an observable. An operator like map or tap wouldn't 
      // work here, as they don't handle subscribing to inner observables.
      this.myService.getFilteredList(searchTerm)
    )
  );

这是模板:

<form class="example-form" [formGroup]="form">
  <mat-form-field appearance="fill">
    <mat-label>Search...</mat-label>
    <input
      class="example-full-width"
      placeholder="Search for something..."
      formControlName="shoppingListSearch"
      [matAutocomplete]="auto"
      matInput
    />
  </mat-form-field>

  <mat-autocomplete #auto="matAutocomplete" [displayWith]="entry">
    <!-- Here is where we subscribe to the filtered list observable -->
    <mat-option *ngFor="let shoppingItem of filteredList$ | async" [value]="shoppingItem.name">
      shoppingItem.name
    </mat-option>
  </mat-autocomplete>
</form>

这是StackBlitz。

【讨论】:

【参考方案2】:

如果我正确地看到了你的代码,你就订阅了 observable。因此,您不会在模板中获得数组值,而是在订阅中。您应该删除 subscribe 方法以使模板正常工作,或者将值保存在 subscribe 方法中并在没有 observables 的情况下使用它。 我不完全理解您想在示例中使用“filteredList”做什么,但您可以将代码包装在点击运算符 https://rxjs.dev/api/operators/tap

【讨论】:

以上是关于使用 formArray 时出现 Mat-AutoComplete 错误的主要内容,如果未能解决你的问题,请参考以下文章

在服务中使用 FormArray 时的 OnPush 更改检测

angular FormArray用法指南

Angular Material MatChipList - 如何在动态 FormArray 上使用它?

2个formarray内的嵌套复选框 - 角度材料

以角度6动态加载formarray中的多个下拉列表

html 响应式表单:使用FormArray