【问题标题】:Angular: create dynamic Reactive Form after async call & AsyncPipeAngular:在异步调用和 AsyncPipe 之后创建动态响应式表单
【发布时间】:2019-12-11 00:57:57
【问题描述】:

我执行异步服务调用以获取元素列表。

 public elementList: Array<Element>;
   ... 
   this.service.getElementList().subscribe( list => {
       this.elementList = list;
       this.createFormGroup(list);
     }
   );
   ...

当我收到元素列表(我订阅了服务调用)时,我会根据元素列表构建表单组。 在模板中,我有一个 *ngIf 来绘制仅当列表大于零时。

*ngIf="elementList?.length>0"

由于elementList是异步获取的,所以这个ngIf不起作用。我读过我可以将 ngIf 与 AsnycPipe 一起使用。所以在模板中我会有:

*ngIf="elementList$ && elementList$.length>0"

其中 elementList$ 是服务调用返回的 Observable。

   public elementList$: Observable<Array<Element>>;   

   elementList$ =this.service.getElementList()

我想知道收到 elementList 后如何创建 FormGroup。首先我需要创建 FormGroup,然后模板应该调用 *ngIf 来绘制元素。

【问题讨论】:

  • 是否可以在StackBlitz 上创建一个最小的示例代码示例来使用?
  • 我在stackblitz.com/edit/angular-4l9rzb 中创建了一个示例。我在模板中使用 elementList$ 来呈现元素,并在组件中使用将 FormControl 添加到 FormGroup 中。这是正确的?

标签: angular angular-reactive-forms async-pipe


【解决方案1】:

可以有许多不同的方法来做到这一点。我现在只分享两种方法,如果你觉得这些方法中的任何一种都不能满足你的用例,我们可以考虑另一种方法(前提是你提供更多关于你想要在这里实现的目标的信息) .

方法一:

您的组件上有两个属性:

form$: Observable<FormGroup>;
list: Array<Element>;

一旦您获得 API 响应,而不是 subscribe 给它,您 map 它并生成一个表单,同时还将响应的值分配给您声明的 list 属性。像这样的:

this.form$ = this.service.getElements()
  .pipe(
    map((list: Array<Element>) => {
      this.list = list;
      return this.fb.group({
        elementId: [list[0].id],
        elementDescription: [list[0].description]
      });
    })
  );

然后你在模板中使用它,有点像这样:

<form 
  *ngIf="form$ | async as form"
  [formGroup]="form">
  <label for="">Element Id: </label>
  <select formControlName="elementId">
    <option 
      *ngFor="let element of list"
      [value]="element.id">
      {{ element.id }}
    </option>
  </select>
  <br>
  <label for="">Element description: </label>
  <select formControlName="elementDescription">
    <option 
      *ngFor="let element of list"
      [value]="element.description">
      {{ element.description }}
    </option>
  </select>
</form>

方法二:

您可能希望将列表和FormGroup 合并在一起。所以你可以在你的组件中创建一个属性:

elementListWithForm$: Observable<{ list: Array<Element>, form: FormGroup }>;

然后你会像这样分配一个值:

this.elementListWithForm$ = this.service.getElements()
  .pipe(
    map((list: Array<Element>) => ({ 
      form: this.fb.group({
        elementId: [list[0].id],
        elementDescription: [list[0].description]
      }),
      list,
     }))
  );

然后你可以像这样在模板中使用它:

<form 
  *ngIf="(elementListWithForm$ | async) as formWithList"
  [formGroup]="formWithList.form">
  <label for="">Element Id: </label>
  <select formControlName="elementId">
    <option 
      *ngFor="let element of formWithList.list"
      [value]="element.id">
      {{ element.id }}
    </option>
  </select>
  <br>
  <label for="">Element description: </label>
  <select formControlName="elementDescription">
    <option 
      *ngFor="let element of formWithList.list"
      [value]="element.description">
      {{ element.description }}
    </option>
  </select>
</form>

这里有一个Working Code Sample on StackBlitz 供您参考。

PS:这种方法的灵感来自我在一篇关于increasing the performance of a deeply nested reactive form in Angular for AngularInDepth 的文章中使用的方法。您可能也想检查一下。

希望这会有所帮助。 :)

【讨论】:

  • 我只是想知道我是否有一个保存按钮(POST 或 PUT 服务 http api 调用)来保存表单中的所有信息,我如何使用 rxjs 从form$: Observable&lt;FormGroup&gt; 获取值?可以分享你的想法吗?谢谢。
  • @Bigeyes,您可以将该信息从模板传递给 TS 类。所以像&lt;button (click)="handleFormSubmit(formWithList.form.value)"&gt;Save&lt;/button&gt;
【解决方案2】:

根据@SiddAjmera 的回答,我构建了第三种满足我需求的选项。

方法3:

formGroup: FormGroup;
elementList$: Observable<Array<Element>>;

收到 API 响应后:

    this.elementList$ = this.service.getElements()
    .pipe(
        map((list: Array<Element>) => {
            this.formGroup = this.fb.group({
                elementId:          [list[0].id],
                elementDescription: [list[0].description]
            });
            return list;
        })
    );

然后在模板中我有这个:

    <form
      *ngIf="(elementList$ | async) as list"
            [formGroup]="formGroup"  (ngSubmit)="onSubmit()">
      <label for=''>Element Id: </label>
      <select formControlName="elementId">
        <option
                *ngFor="let element of list"
                [value]="element.id">
          {{ element.id }}
        </option>
      </select>
      <br>
      <label for=''>Element description: </label>
      <select formControlName="elementDescription">
        <option
                *ngFor="let element of list"
                [value]="element.description">
          {{ element.description }}
        </option>
      </select>  
      <br>
      <button type="submit">Click</button
</form>

在组件中,当我单击按钮时,我会访问表单组以获取值:

public onSubmit() {
    console.log(this.formGroup.toString());
}

【讨论】:

    【解决方案3】:

    首先(但只是挑剔),我相信“绘画”元素的正确术语是“渲染”元素。(说实话,我对你的术语没意见使用。)

    关于问题本身,您可以通过管道将Observable 列表通过async 管道检查列表的长度,然后检查该管道列表的长度:

    *ngIf="elementList$ && (elementList$ | async)?.length > 0"
    

    【讨论】:

    • 然后我可以访问组件中的elementList$来构建FormGroup吗?
    猜你喜欢
    • 2019-07-28
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 2019-05-31
    • 2019-10-10
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多