为什么表单控件以反应形式显示 [Object][Object]?
why form control is showing [Object][Object] in reactive form?
我有 functions
可以动态创建 reactive
表单。我只需要通过 array
of feilds
.
这是我的 service
中的函数
createForm(fieldsArr: any[]) {
let formObject = {};
fieldsArr.forEach(f => {
if(f.isArray){
if(f.defaultValue === null){
formObject[f.name] = this.fb.array([]);
} else {
formObject[f.name] = this.fb.array([this.createArrayType(f.nestedFieldsArr)]);
}
} else {
formObject[f.name] = [f.defaultValue ? f.defaultValue : '', f.isRequired ? Validators.required : Validators.nullValidator];
}
})
return this.fb.group(formObject);
}
createArrayType(nestedFieldsArr: any[]) {
let nestedFormObj = {};
nestedFieldsArr.forEach(f => {
nestedFormObj[f.name] = [[{ value: f.defaultValue ? f.defaultValue : '', disabled: f.isDisabled ? true : false }], f.isRequired ? Validators.required : Validators.nullValidator]
})
let form = this.fb.group(nestedFormObj);
return form;
}
这是 fields
的 array
,我将其传递给 function
以创建 reactive-form
public marketPlaceFormFields = [
{
name: 'pickupLocations',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false,
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'deliveryLocations',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'waypoints',
isRequired: true,
isArray: true,
defaultValue: null,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false
},
{
name: 'type',
isRequired: false
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'bidVehicles',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'vehicleLoadId',
isRequired: false,
defaultValue: 0
},
{
name: 'categoryId',
isRequired: true
},
{
name: 'numberOfVehicles',
isRequired: true
},
{
name: 'loadRequirementId',
isRequired: false,
defaultValue: 1
}
]
},
{
name: 'shipmentWeight',
isRequired: true
},
{
name: 'budgetMin',
isRequired: true
},
{
name: 'budgetMax',
isRequired: true
},
{
name: 'paymentTerm',
isRequired: false,
defaultValue: 'Cash on Delivery'
},
{
name: 'bidDateFrom',
isRequired: true
},
{
name: 'bidDateTo',
isRequired: true
},
{
name: 'orderId',
isRequired: false
},
{
name: 'insertedBy',
isRequired: false
},
{
name: 'shipperId',
isRequired: false
}
];
component.ts
get pickLocatons() { return this.frm.pickupLocations as FormArray; }
ngOnInit(){
this.marketForm = this.us.createForm(this.constants.marketPlaceFormFields);
}
component.html
<ng-container *ngFor="let pickControl of pickLocatons.controls; let i = index">
<div class="row" [formGroup]="pickControl">
<div class="col-md-3">
<div class="form-group">
<label>
Pick up Location
<span class="text-danger font-bold ml-1">*</span>
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.pickup}}" popoverClass="op-popover"></i>
</label>
<div class="input-group">
<input type="text" class="form-control" placeholder="Bazar Kharadan, Koh..." formControlName="location" [ngClass]="{'is-invalid' : pickControl.get('location')?.errors &&
(pickControl.get('location').touched || pickControl.get('location').dirty)}" />
<div class="input-group-append cursor-pointer" (click)="openMapModal('pickupLoc', i)">
<span class="input-group-text"><i class="fa fa-map-marker px-1"></i></span>
</div>
</div>
<span class="help-block" *ngIf="pickControl.get('location')?.errors &&
(pickControl.get('location').touched || pickControl.get('location').dirty)">
<span *ngIf="pickControl.get('location')?.errors?.required" class="text-danger">
{{constants.errors.required.location}}
</span>
</span>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>
<!-- <i class="fa fa-map-marker color-primary" aria-hidden="true"></i> -->
Add Corresponding Code
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.code}}" popoverClass="op-popover"></i>
</label>
<input type="text" class="form-control" placeholder="Code" formControlName="locationCode" />
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>
<!-- <i class="fa fa-calendar-o color-primary" aria-hidden="true"></i> -->
Date/Time
<span class="text-danger font-bold ml-1">*</span>
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.picDate}}" popoverClass="op-popover"></i>
</label>
<input type="datetime-local" class="form-control" formControlName="dateTime" min="{{ (minDate | date: 'yyyy-MM-dd') + 'T00:00' }}" [max]="eConfig.DATETIME_MAX" [ngClass]="{'is-invalid' : pickControl.get('dateTime')?.errors &&
(pickControl.get('dateTime').touched || pickControl.get('dateTime').dirty)}">
<span class="help-block" *ngIf="pickControl.get('dateTime')?.errors &&
(pickControl.get('dateTime').touched || pickControl.get('dateTime').dirty)">
<span *ngIf="pickControl.get('dateTime')?.errors?.required" class="text-danger">
This is required
</span>
</span>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<button class="btn btn-primary rounded-0 mt-28" (click)="addLocation()" *ngIf="i === 0">+ Add Stop</button>
<button class="btn btn-primary rounded-0 mt-28" (click)="removeLocation(i)" *ngIf="i > 0">+ Remove</button>
</div>
</div>
但问题是当页面加载时,表单数组字段显示 [object][object] 作为输入的值
我不知道为什么表单域在页面加载后显示 [object][object]
注意:我只在 post.
中包含了必要的代码
据我了解,您有一个 FormGroup,其中包含一个 FormArray,其中包含一个包含 1 个 FormGroup 的列表,其中包含您的 FormControl。在 HTML 中,您需要一个 FormGroup,其中包含一个 FormArray,其中包含一个 FormControl 列表。所以看起来你嵌套太多了,或者在 HTML 中没有足够的 decaplusated。从您的评论来看,您似乎需要 FormArray,因此这是一个更新的解决方案:
createForm(fieldsArr: any[]) {
const formGroup = new FormGroup({});
fieldsArr.forEach(f => {
if(f.isArray){
if(f.defaultValue === null){
// seems to never happen ? because you would need 1 default value for each element of your array, not just one defaultValue.
// formObject[f.name] = this.fb.array([]);
} else {
formGroup.addControl(f.name, this.createNestedFormArray(f.nestedFieldsArr)); // removed the FormArray layer
}
} else {
const formControl = new FormControl(f.defaultValue ? f.defaultValue : '',
f.isRequired ? Validators.required : Validators.nullValidator);
formGroup.addControl(f.name, formControl);
// formObject[f.name] = [f.defaultValue ? f.defaultValue : '', f.isRequired ? Validators.required : Validators.nullValidator];
}
});
return formGroup;
}
createNestedFormArray(nestedFieldsArr: any[]) {
const nestedFormGroup = new FormGroup({});
nestedFieldsArr.forEach(f => {
const formControl = new FormControl(f.defaultValue ? f.defaultValue : '',
f.isRequired ? Validators.required : Validators.nullValidator);
if ( f.isDisabled ) {
formControl.disable(); // moved disabled logic from constructor (not valid)
}
nestedFormGroup.addControl(f.name, formControl);
// nestedFormObj[f.name] = [[{ value: f.defaultValue ? f.defaultValue : '', disabled: f.isDisabled ? true : false }], f.isRequired ? Validators.required : Validators.nullValidator]
})
return new FormArray([nestedFormGroup]);
}
并且在 HTML 中循环 FormArray:
<ng-container *ngFor="let pickArray of pickLocatons.controls">
<!-- pickArray is the FormArray, containing multiple FormGroups -->
<ng-container *ngFor="let pickNestedGroup of pickArray; let i = index" [formGroupName]="i">
<!-- pickNestedGroup is the FormGroup, containing multiple FormControls (location, lat, long...) -->
<!-- [formGroupName]="i" means you are using the ith element of the FormArray as reference for every following formControlNames, instead of the parent one -->
<input formControlName="location"/>
我有 functions
可以动态创建 reactive
表单。我只需要通过 array
of feilds
.
这是我的 service
createForm(fieldsArr: any[]) {
let formObject = {};
fieldsArr.forEach(f => {
if(f.isArray){
if(f.defaultValue === null){
formObject[f.name] = this.fb.array([]);
} else {
formObject[f.name] = this.fb.array([this.createArrayType(f.nestedFieldsArr)]);
}
} else {
formObject[f.name] = [f.defaultValue ? f.defaultValue : '', f.isRequired ? Validators.required : Validators.nullValidator];
}
})
return this.fb.group(formObject);
}
createArrayType(nestedFieldsArr: any[]) {
let nestedFormObj = {};
nestedFieldsArr.forEach(f => {
nestedFormObj[f.name] = [[{ value: f.defaultValue ? f.defaultValue : '', disabled: f.isDisabled ? true : false }], f.isRequired ? Validators.required : Validators.nullValidator]
})
let form = this.fb.group(nestedFormObj);
return form;
}
这是 fields
的 array
,我将其传递给 function
以创建 reactive-form
public marketPlaceFormFields = [
{
name: 'pickupLocations',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false,
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'deliveryLocations',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'waypoints',
isRequired: true,
isArray: true,
defaultValue: null,
nestedFieldsArr: [
{
name: 'location',
isRequired: true
},
{
name: 'lat',
isRequired: false
},
{
name: 'long',
isRequired: false
},
{
name: 'locationCode',
isRequired: false
},
{
name: 'type',
isRequired: false
},
{
name: 'dateTime',
isRequired: true
}
]
},
{
name: 'bidVehicles',
isRequired: true,
isArray: true,
nestedFieldsArr: [
{
name: 'vehicleLoadId',
isRequired: false,
defaultValue: 0
},
{
name: 'categoryId',
isRequired: true
},
{
name: 'numberOfVehicles',
isRequired: true
},
{
name: 'loadRequirementId',
isRequired: false,
defaultValue: 1
}
]
},
{
name: 'shipmentWeight',
isRequired: true
},
{
name: 'budgetMin',
isRequired: true
},
{
name: 'budgetMax',
isRequired: true
},
{
name: 'paymentTerm',
isRequired: false,
defaultValue: 'Cash on Delivery'
},
{
name: 'bidDateFrom',
isRequired: true
},
{
name: 'bidDateTo',
isRequired: true
},
{
name: 'orderId',
isRequired: false
},
{
name: 'insertedBy',
isRequired: false
},
{
name: 'shipperId',
isRequired: false
}
];
component.ts
get pickLocatons() { return this.frm.pickupLocations as FormArray; }
ngOnInit(){
this.marketForm = this.us.createForm(this.constants.marketPlaceFormFields);
}
component.html
<ng-container *ngFor="let pickControl of pickLocatons.controls; let i = index">
<div class="row" [formGroup]="pickControl">
<div class="col-md-3">
<div class="form-group">
<label>
Pick up Location
<span class="text-danger font-bold ml-1">*</span>
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.pickup}}" popoverClass="op-popover"></i>
</label>
<div class="input-group">
<input type="text" class="form-control" placeholder="Bazar Kharadan, Koh..." formControlName="location" [ngClass]="{'is-invalid' : pickControl.get('location')?.errors &&
(pickControl.get('location').touched || pickControl.get('location').dirty)}" />
<div class="input-group-append cursor-pointer" (click)="openMapModal('pickupLoc', i)">
<span class="input-group-text"><i class="fa fa-map-marker px-1"></i></span>
</div>
</div>
<span class="help-block" *ngIf="pickControl.get('location')?.errors &&
(pickControl.get('location').touched || pickControl.get('location').dirty)">
<span *ngIf="pickControl.get('location')?.errors?.required" class="text-danger">
{{constants.errors.required.location}}
</span>
</span>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>
<!-- <i class="fa fa-map-marker color-primary" aria-hidden="true"></i> -->
Add Corresponding Code
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.code}}" popoverClass="op-popover"></i>
</label>
<input type="text" class="form-control" placeholder="Code" formControlName="locationCode" />
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>
<!-- <i class="fa fa-calendar-o color-primary" aria-hidden="true"></i> -->
Date/Time
<span class="text-danger font-bold ml-1">*</span>
<i class="fa fa-info-circle ml-1 color-primary cursor-pointer" placement="auto"
ngbPopover="{{constants.popovers.bid.picDate}}" popoverClass="op-popover"></i>
</label>
<input type="datetime-local" class="form-control" formControlName="dateTime" min="{{ (minDate | date: 'yyyy-MM-dd') + 'T00:00' }}" [max]="eConfig.DATETIME_MAX" [ngClass]="{'is-invalid' : pickControl.get('dateTime')?.errors &&
(pickControl.get('dateTime').touched || pickControl.get('dateTime').dirty)}">
<span class="help-block" *ngIf="pickControl.get('dateTime')?.errors &&
(pickControl.get('dateTime').touched || pickControl.get('dateTime').dirty)">
<span *ngIf="pickControl.get('dateTime')?.errors?.required" class="text-danger">
This is required
</span>
</span>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<button class="btn btn-primary rounded-0 mt-28" (click)="addLocation()" *ngIf="i === 0">+ Add Stop</button>
<button class="btn btn-primary rounded-0 mt-28" (click)="removeLocation(i)" *ngIf="i > 0">+ Remove</button>
</div>
</div>
但问题是当页面加载时,表单数组字段显示 [object][object] 作为输入的值
我不知道为什么表单域在页面加载后显示 [object][object]
注意:我只在 post.
中包含了必要的代码据我了解,您有一个 FormGroup,其中包含一个 FormArray,其中包含一个包含 1 个 FormGroup 的列表,其中包含您的 FormControl。在 HTML 中,您需要一个 FormGroup,其中包含一个 FormArray,其中包含一个 FormControl 列表。所以看起来你嵌套太多了,或者在 HTML 中没有足够的 decaplusated。从您的评论来看,您似乎需要 FormArray,因此这是一个更新的解决方案:
createForm(fieldsArr: any[]) {
const formGroup = new FormGroup({});
fieldsArr.forEach(f => {
if(f.isArray){
if(f.defaultValue === null){
// seems to never happen ? because you would need 1 default value for each element of your array, not just one defaultValue.
// formObject[f.name] = this.fb.array([]);
} else {
formGroup.addControl(f.name, this.createNestedFormArray(f.nestedFieldsArr)); // removed the FormArray layer
}
} else {
const formControl = new FormControl(f.defaultValue ? f.defaultValue : '',
f.isRequired ? Validators.required : Validators.nullValidator);
formGroup.addControl(f.name, formControl);
// formObject[f.name] = [f.defaultValue ? f.defaultValue : '', f.isRequired ? Validators.required : Validators.nullValidator];
}
});
return formGroup;
}
createNestedFormArray(nestedFieldsArr: any[]) {
const nestedFormGroup = new FormGroup({});
nestedFieldsArr.forEach(f => {
const formControl = new FormControl(f.defaultValue ? f.defaultValue : '',
f.isRequired ? Validators.required : Validators.nullValidator);
if ( f.isDisabled ) {
formControl.disable(); // moved disabled logic from constructor (not valid)
}
nestedFormGroup.addControl(f.name, formControl);
// nestedFormObj[f.name] = [[{ value: f.defaultValue ? f.defaultValue : '', disabled: f.isDisabled ? true : false }], f.isRequired ? Validators.required : Validators.nullValidator]
})
return new FormArray([nestedFormGroup]);
}
并且在 HTML 中循环 FormArray:
<ng-container *ngFor="let pickArray of pickLocatons.controls">
<!-- pickArray is the FormArray, containing multiple FormGroups -->
<ng-container *ngFor="let pickNestedGroup of pickArray; let i = index" [formGroupName]="i">
<!-- pickNestedGroup is the FormGroup, containing multiple FormControls (location, lat, long...) -->
<!-- [formGroupName]="i" means you are using the ith element of the FormArray as reference for every following formControlNames, instead of the parent one -->
<input formControlName="location"/>