Angular: 在异步调用和 AsyncPipe 之后创建动态响应式表单
Angular: create dynamic Reactive Form after async call & AsyncPipe
我执行异步服务调用以获取元素列表。
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 来绘制元素。
首先(但只是吹毛求疵),我认为 "painting" 元素的正确术语应该是 "rendering" 元素。(老实说,我对你使用的术语没问题。)
关于问题本身,您可以通过管道 Observable
列表通过 async
管道检查列表的长度,然后检查该管道列表的长度:
*ngIf="elementList$ && (elementList$ | async)?.length > 0"
可以有许多不同的方法来实现这一点。我现在只分享两种方法,如果您觉得这些方法中的任何一种不能满足您的用例,我们可以考虑采用不同的方法(前提是您提供更多信息,说明您究竟想在此处实现什么) .
方法一:
您的组件有两个属性:
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>
Here's a Working Code Sample on StackBlitz for your ref.
PS: This approach is heavily inspired by the one I used in an article that I wrote about increasing the performance of a deeply nested reactive form in Angular for AngularInDepth. You might want to check that out as well.
希望这对您有所帮助。 :)
根据@SiddAjmera的回答,我构建了满足我需求的第三个选项。
方法三:
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());
}
我执行异步服务调用以获取元素列表。
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 来绘制元素。
首先(但只是吹毛求疵),我认为 "painting" 元素的正确术语应该是 "rendering" 元素。(老实说,我对你使用的术语没问题。)
关于问题本身,您可以通过管道 Observable
列表通过 async
管道检查列表的长度,然后检查该管道列表的长度:
*ngIf="elementList$ && (elementList$ | async)?.length > 0"
可以有许多不同的方法来实现这一点。我现在只分享两种方法,如果您觉得这些方法中的任何一种不能满足您的用例,我们可以考虑采用不同的方法(前提是您提供更多信息,说明您究竟想在此处实现什么) .
方法一:
您的组件有两个属性:
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>
Here's a Working Code Sample on StackBlitz for your ref.
PS: This approach is heavily inspired by the one I used in an article that I wrote about increasing the performance of a deeply nested reactive form in Angular for AngularInDepth. You might want to check that out as well.
希望这对您有所帮助。 :)
根据@SiddAjmera的回答,我构建了满足我需求的第三个选项。
方法三:
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());
}