Angular5/4+:使用 API 调用填充嵌套的 ReactiveForm
Angular5/4+: Populate nested ReactiveForm using API call
我正在尝试填充嵌套的 ReactiveForm
,它被分成几个子表单组件。一旦 API 请求完成,我就可以填充父表单,但不能将子 FormArray
精确地循环到子数据的计数。以下是我的代码片段:
编辑视图:edit.component.ts
@Component({
selector: 'app-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.scss']
})
export class EditComponent implements OnInit {
public data: Service = new Service({
id: '',
title: '',
description: '',
service_extras: []
});
public routeParams: any = {};
constructor (
private route: ActivatedRoute,
private service: ServicesService
) { }
ngOnInit() {
this.setRouteParams();
}
setRouteParams() {
this.route.params.subscribe(params => {
this.routeParams = params;
// getting services using api call
this.getService(this.routeParams);
});
}
getService(params) {
this.service
.getService(params.id)
.subscribe((service: Service) => {
this.data = service;
});
}
}
我在基础 edit.component.ts
组件中请求数据并将接收到的数据传递给作为 EditComponent
子级的父表单组件
edit.component.html
<service-form [serviceFormData]="data"></service-form>
服务-form.component.ts
@Component({
selector: 'service-form',
templateUrl: './service-form.component.html',
styleUrls: ['./service-form.component.scss']
})
export class ServiceFormComponent implements OnInit {
private _serviceFormData = new BehaviorSubject<Service>(null);
@Input()
set serviceFormData(value) {
this._serviceFormData.next(value);
}
get serviceFormData() {
return this._serviceFormData.getValue();
}
public service: Service;
public serviceForm: FormGroup;
constructor(
private fb: FormBuilder
) { }
ngOnInit() {
this.serviceForm = this.toFormGroup();
this._serviceFormData.subscribe(data => {
this.serviceForm.patchValue(data);
});
}
private toFormGroup(): FormGroup {
const formGroup = this.fb.group({
id: [ '' ],
title: [ '' ],
description: [ '' ]
});
return formGroup;
}
}
我在 @Input
var 的帮助下接收数据,方法是订阅其更改,然后将值修补到表单,现在一切正常,因为一旦收到数据,所有字段都会被填充.问题如下:
服务-extra.component.ts
@Component({
selector: 'service-extra-form',
templateUrl: './service-extra.component.html',
styleUrls: ['./service-extra.component.scss']
})
export class ServiceExtraComponent implements OnInit {
private _extraFormData = new BehaviorSubject<ServiceExtra[]>([]);
@Input() serviceForm: FormGroup;
@Input()
set extraFormData(value: ServiceExtra[]) {
this._extraFormData.next(value);
}
get extraFormData() {
return this._extraFormData.getValue();
}
public extrasForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit()
{
this.serviceForm.addControl('service_extras', new FormArray([]));
this._extraFormData.subscribe(data => {
this.addNew();
this.extras.patchValue(data);
});
}
private toFormGroup()
{
const formGroup = this.fb.group({
id: [''],
service_id: [''],
title: ['']
});
return formGroup;
}
public addNew()
{
this.extrasForm = this.toFormGroup(); (<FormArray>this.serviceForm.controls.service_extras).push(this.extrasForm);
}
public removeThis(i: number)
{
(<FormArray>this.serviceForm.controls.service_extras).removeAt(i);
}
get extras(): FormArray {
return this.serviceForm.get('service_extras') as FormArray;
}
}
上面的 ngOnInit
代码除了添加单个附加表单(即使有两条记录)并填充该表单外什么都不做,即使我删除订阅部分并仅使用 this.addNew()
.我如何知道 ServiceExtras
有多少条记录,以便我可以将那么多 FormGroups
添加到 FormArray
。
编辑 1
Stackblitz Demo
编辑 2
问题是,如果有两条记录来自 API 用于额外服务,那么我无法生成两条 FormGroups
并用数据填充它们,因为在渲染时我无法检测到来自 API.
的额外服务有多少条记录
这是一个修复 (stackblitz here)
问题行为的解释:
您的输入是这样声明的:
<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceForm.value.service_extra"></service-extra-form>
所以输入的是表单的值,而不是来自 api 的值。
但是当您在对 api 进行异步调用后填充表单时,第一个值 "sent" 到 ServiceExtraComponent
是 undefined
并且在 ServiceExtraComponent
ngOnInit
你叫
this.addNew();
this.extras.patchValue(data);
和data = undefined
它在 formArray 中创建一个新的 formGroup,然后使用 undefined 进行修补。
因此,当 API 响应时,您的表单已使用包含一项的 formArray 创建,因此 patchValue
截断您的 service_extra 数组以匹配您的表单。
更正可能是将 API 的 return 直接绑定为 ServiceExtraComponent
Input
又名:
<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceFormData.service_extras"></service-extra-form>
在 service-form.component.html
中,您将 serviceForm.value.service_extras
属性 绑定到 extraFormData
。但是在 service-extra-form
组件初始化之前 serviceForm
没有 service_extras formArray。在初始化之后。 service-extra-form
组件,您调用 addRow()
方法,该方法正好用一行填充表单:
服务-extra.component.ts:
ngOnInit()
{
this.serviceForm.addControl('service_extras', new FormArray([]));
this._extraFormData.subscribe(data => {
console.log('service_extra_data', data);
this.addNew();
this.extras.patchValue(data);
});
}
服务-form.component.html:
<service-extra-form [serviceForm]="serviceForm"
[extraFormData]="serviceForm.value.service_extras">
</service-extra-form>
将 [serviceForm] 传递给 service-extra-form
就足够了。为什么你通过 serviceForm.value.service_extras
,如果你已经通过 form
?
修复,删除多余的代码。用更少的代码做同样的事情
ServiceExtraComponent:
export class ServiceExtraComponent implements OnInit {
@Input() serviceForm: FormGroup;
@Input() extraFormData: ServiceExtra[];
public extrasForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnChanges(data) {
//console.log('ngOnChanges', data);
// if changes only extraFormData
if (data.extraFormData) {
this.extras.setValue([]); // reset
let newExtraArr = data.extraFormData.currentValue;
for (let i = 0; i < newExtraArr.length; i++) {
this.addNew();
this.extras.patchValue(newExtraArr);
}
}
}
ngOnInit() {
this.serviceForm.addControl('service_extras', new FormArray([]));
}
@Input() extraFormData: ServiceExtra[];
这里从 api 传递 extra_data
并在 ngOnChanges
lyfecycle 挂钩上,重置 serviceForm 的 service_extras
formArray
我正在尝试填充嵌套的 ReactiveForm
,它被分成几个子表单组件。一旦 API 请求完成,我就可以填充父表单,但不能将子 FormArray
精确地循环到子数据的计数。以下是我的代码片段:
编辑视图:edit.component.ts
@Component({
selector: 'app-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.scss']
})
export class EditComponent implements OnInit {
public data: Service = new Service({
id: '',
title: '',
description: '',
service_extras: []
});
public routeParams: any = {};
constructor (
private route: ActivatedRoute,
private service: ServicesService
) { }
ngOnInit() {
this.setRouteParams();
}
setRouteParams() {
this.route.params.subscribe(params => {
this.routeParams = params;
// getting services using api call
this.getService(this.routeParams);
});
}
getService(params) {
this.service
.getService(params.id)
.subscribe((service: Service) => {
this.data = service;
});
}
}
我在基础 edit.component.ts
组件中请求数据并将接收到的数据传递给作为 EditComponent
edit.component.html
<service-form [serviceFormData]="data"></service-form>
服务-form.component.ts
@Component({
selector: 'service-form',
templateUrl: './service-form.component.html',
styleUrls: ['./service-form.component.scss']
})
export class ServiceFormComponent implements OnInit {
private _serviceFormData = new BehaviorSubject<Service>(null);
@Input()
set serviceFormData(value) {
this._serviceFormData.next(value);
}
get serviceFormData() {
return this._serviceFormData.getValue();
}
public service: Service;
public serviceForm: FormGroup;
constructor(
private fb: FormBuilder
) { }
ngOnInit() {
this.serviceForm = this.toFormGroup();
this._serviceFormData.subscribe(data => {
this.serviceForm.patchValue(data);
});
}
private toFormGroup(): FormGroup {
const formGroup = this.fb.group({
id: [ '' ],
title: [ '' ],
description: [ '' ]
});
return formGroup;
}
}
我在 @Input
var 的帮助下接收数据,方法是订阅其更改,然后将值修补到表单,现在一切正常,因为一旦收到数据,所有字段都会被填充.问题如下:
服务-extra.component.ts
@Component({
selector: 'service-extra-form',
templateUrl: './service-extra.component.html',
styleUrls: ['./service-extra.component.scss']
})
export class ServiceExtraComponent implements OnInit {
private _extraFormData = new BehaviorSubject<ServiceExtra[]>([]);
@Input() serviceForm: FormGroup;
@Input()
set extraFormData(value: ServiceExtra[]) {
this._extraFormData.next(value);
}
get extraFormData() {
return this._extraFormData.getValue();
}
public extrasForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit()
{
this.serviceForm.addControl('service_extras', new FormArray([]));
this._extraFormData.subscribe(data => {
this.addNew();
this.extras.patchValue(data);
});
}
private toFormGroup()
{
const formGroup = this.fb.group({
id: [''],
service_id: [''],
title: ['']
});
return formGroup;
}
public addNew()
{
this.extrasForm = this.toFormGroup(); (<FormArray>this.serviceForm.controls.service_extras).push(this.extrasForm);
}
public removeThis(i: number)
{
(<FormArray>this.serviceForm.controls.service_extras).removeAt(i);
}
get extras(): FormArray {
return this.serviceForm.get('service_extras') as FormArray;
}
}
上面的 ngOnInit
代码除了添加单个附加表单(即使有两条记录)并填充该表单外什么都不做,即使我删除订阅部分并仅使用 this.addNew()
.我如何知道 ServiceExtras
有多少条记录,以便我可以将那么多 FormGroups
添加到 FormArray
。
编辑 1
Stackblitz Demo
编辑 2
问题是,如果有两条记录来自 API 用于额外服务,那么我无法生成两条 FormGroups
并用数据填充它们,因为在渲染时我无法检测到来自 API.
这是一个修复 (stackblitz here)
问题行为的解释:
您的输入是这样声明的:
<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceForm.value.service_extra"></service-extra-form>
所以输入的是表单的值,而不是来自 api 的值。
但是当您在对 api 进行异步调用后填充表单时,第一个值 "sent" 到 ServiceExtraComponent
是 undefined
并且在 ServiceExtraComponent
ngOnInit
你叫
this.addNew();
this.extras.patchValue(data);
和data = undefined
它在 formArray 中创建一个新的 formGroup,然后使用 undefined 进行修补。
因此,当 API 响应时,您的表单已使用包含一项的 formArray 创建,因此 patchValue
截断您的 service_extra 数组以匹配您的表单。
更正可能是将 API 的 return 直接绑定为 ServiceExtraComponent
Input
又名:
<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceFormData.service_extras"></service-extra-form>
在 service-form.component.html
中,您将 serviceForm.value.service_extras
属性 绑定到 extraFormData
。但是在 service-extra-form
组件初始化之前 serviceForm
没有 service_extras formArray。在初始化之后。 service-extra-form
组件,您调用 addRow()
方法,该方法正好用一行填充表单:
服务-extra.component.ts:
ngOnInit()
{
this.serviceForm.addControl('service_extras', new FormArray([]));
this._extraFormData.subscribe(data => {
console.log('service_extra_data', data);
this.addNew();
this.extras.patchValue(data);
});
}
服务-form.component.html:
<service-extra-form [serviceForm]="serviceForm"
[extraFormData]="serviceForm.value.service_extras">
</service-extra-form>
将 [serviceForm] 传递给 service-extra-form
就足够了。为什么你通过 serviceForm.value.service_extras
,如果你已经通过 form
?
修复,删除多余的代码。用更少的代码做同样的事情
ServiceExtraComponent:
export class ServiceExtraComponent implements OnInit {
@Input() serviceForm: FormGroup;
@Input() extraFormData: ServiceExtra[];
public extrasForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnChanges(data) {
//console.log('ngOnChanges', data);
// if changes only extraFormData
if (data.extraFormData) {
this.extras.setValue([]); // reset
let newExtraArr = data.extraFormData.currentValue;
for (let i = 0; i < newExtraArr.length; i++) {
this.addNew();
this.extras.patchValue(newExtraArr);
}
}
}
ngOnInit() {
this.serviceForm.addControl('service_extras', new FormArray([]));
}
@Input() extraFormData: ServiceExtra[];
这里从 api 传递 extra_data
并在 ngOnChanges
lyfecycle 挂钩上,重置 serviceForm 的 service_extras
formArray