Angular 4 反应形式 - FormArray Within FormArray 无法获取路径
Angular 4 reactive form - FormArray Within FormArray unable to get path
几天来,我一直在尝试创建一个表单,让用户可以创建产品,同时可以创建与父产品价格不同的产品变体。例如,大部件是 10 英镑,小部件是 5 英镑。我每次最终得到的都是 FormArray 中的 FormArray,换句话说,我有一个具有一系列变体的产品,这些变体有价格,但也有一系列属性。当我尝试添加控件时出现问题,我可以让变化价格显示得很好,但我无法获得添加 variations.attributes 控件的路径,我只是收到有关 ngFor 的错误仅使用数组而不是 [Object, Object] 或控件为空...我遇到的错误比我记得的还要多!无论如何,我的代码已经重写了很多,可能比开始时更糟糕!
首先是我的 oninit 中的表单:
ngOnInit() {
this.getAttributes(); // Get Attribute Categories
this.form = this.fb.group({
name: [''],
price: [''],
description: [''],
stockRef: [''],
attributes: this.fb.array([{
attributeCategoryId: [''],
name: [''],
}]),
variations: this.fb.array([{
vprice: this.vprice,
vattributes: this.vattributes
}]),
});
}
为主产品添加和删除属性的部分,工作正常:
addAttribute(id: any, name: any) {
if (!id.value || !name.value)
return;
this.attributes = <FormArray>this.form.get('attributes');
var newAttribute = this.fb.group({
attributeCategoryId: [id.value],
name: [name.value],
});
this.newlist.push({ name: [name.value].toString(), attributeCategoryId: [id.value].toString() });
this.attributes.push(newAttribute);
id.value = '';
name.value = '';
}
removeAttr(i: any) {
this.attributes.removeAt(i);
this.list2 = [];
this.newlist.splice(i, 1);
}
我添加变体的部分有效,它仍然有我用来尝试将添加到主要产品的属性复制到变体中的代码,我认为这有效,但就是无法获得访问值以显示它们,variations.attributes 对路径无效。
initVariation() {
let v = this.fb.group({
price: [''],
vattributes: this.attributes //COPIES main attributes
});
this.attributes.reset(); //Reset the main attributes as they now
return v; //belong to a variation
}
addNewVar() {
const control = <FormArray>this.form.controls['variations'];
control.push(this.initVariation());
}
向变体添加属性的部分不起作用,这是我在 component.ts
中遇到问题的地方
addAttrRow() {
const control = <FormArray>this.form.controls['variations.vattributes']
control.push(this.initVattr())
}
initVattr() {
let va = this.fb.group({
vattributeCategoryId: [''],
vname: ['']
})
return va;
}
最后,我的 html 更乱了哈哈:
<h1>New Product</h1>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Product Name</label>
<div *ngIf="!form.get('name').valid" class="alert alert-danger">
{{ form.get('name').getError('remote') }}
</div>
<input [(ngModel)]="name" type="text" formControlName="name" class="form-control">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Price</label>
<div *ngIf="!form.get('price').valid" class="alert alert-danger">
{{ form.get('price').getError('remote') }}
</div>
<input [(ngModel)]="price" type="number" formControlName="price" class="form-control">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Product Description</label>
<div *ngIf="!form.get('description').valid" class="alert alert-danger">
{{ form.get('description').getError('remote') }}
</div>
<textarea formControlName="description" class="form-control"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div>
<h4>Attributes</h4>
<div class="form-inline" >
<div class="form-group">
<div formArrayName="attributes">
<select #ac name="attributeCategoryId">
<option value="" selected>Category</option>
<option *ngFor="let a of attriblist;let i = index" value="{{a.id}}">{{a.name}}</option>
</select>
<input #a name="name" placeholder="Attribute name" />
</div>
</div>
<button type="button" class="btn btn-default" (click)="addAttribute(ac,a)">Add Attribute</button>
</div>
<br>
<table class="table-bordered table table-striped">
<thead>
<tr>
<th>Attr. Category</th>
<th>Attr.</th>
<th><button type="button" (click)="addNewVar()" class="btn btn-primary">Add Variation</button></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let a of form.value.attributes; let i = index;" >
<td *ngIf="i > 0">{{a.attributeCategoryId}}</td>
<td *ngIf="i > 0">{{a.name}}</td>
<td *ngIf="i > 0"><button (click)="removeAttr(i)" class="btn btn-danger">X</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--Variations Start-->
<div class="row" formArrayName="variations">
<div *ngFor="let variation of form.controls.variations.controls; let i=index" [formGroupName]="i">
<h5>Variation #{{ i + 1 }}</h5>
<p></p>
<div class="form-group">
<label>Variation Price</label>
<input name="vprice" style="max-width:50px" class="form-control">
</div>
<table>
<thead>
<tr>
<th>Attr. Category</th>
<th>Attr.</th>
<th><button class="btn btn-success" (click)="addAttrRow()">+</button></th>
</tr>
</thead>
<tbody name="vattributes">
<tr *ngFor="let attribute of variation.get('vattributes'); let ii = index;">
<td><input type="text" name="vattributeCateforyId" /></td>
<td><input type="text" name="vname" /></td>
<td><button (click)="removeVAttr(ii)" class="btn btn-danger">X</button></td>
</tr>
</tbody>
</table>
<button class="btn btn-danger" (click)="removeVariation(i)">Delete</button>
</div>
</div>
<!--Variations End-->
<br>
<p>
<button type="submit" class="btn btn-primary">Save</button>
</p>
</form>
我看到你的代码中有很多错误。
例如
1) 你应该知道在处理从 FormArray
获取控制时我们不需要忘记索引
所以不用
const control = <FormArray>this.form.controls['variations.vattributes'];
我们应该使用
addAttrRow(index) {
const control = <FormArray>this.form.get(['variations', index, 'vattributes']);
2) 如果您没有为 button
指定类型,它将使用 submit
作为默认值。
<button class="btn btn-success" (click)="addAttrRow()">+</button>
这可能会导致不可预知的情况。
所以尝试指定 type="button"
3) 你遍历对象
*ngFor="let attribute of variation.get('vattributes');
而你需要遍历数组
*ngFor="let variation of form.controls.variations.controls;
我创建了 Plunker Example 可以帮助您意识到自己做错了什么
几天来,我一直在尝试创建一个表单,让用户可以创建产品,同时可以创建与父产品价格不同的产品变体。例如,大部件是 10 英镑,小部件是 5 英镑。我每次最终得到的都是 FormArray 中的 FormArray,换句话说,我有一个具有一系列变体的产品,这些变体有价格,但也有一系列属性。当我尝试添加控件时出现问题,我可以让变化价格显示得很好,但我无法获得添加 variations.attributes 控件的路径,我只是收到有关 ngFor 的错误仅使用数组而不是 [Object, Object] 或控件为空...我遇到的错误比我记得的还要多!无论如何,我的代码已经重写了很多,可能比开始时更糟糕!
首先是我的 oninit 中的表单:
ngOnInit() {
this.getAttributes(); // Get Attribute Categories
this.form = this.fb.group({
name: [''],
price: [''],
description: [''],
stockRef: [''],
attributes: this.fb.array([{
attributeCategoryId: [''],
name: [''],
}]),
variations: this.fb.array([{
vprice: this.vprice,
vattributes: this.vattributes
}]),
});
}
为主产品添加和删除属性的部分,工作正常:
addAttribute(id: any, name: any) {
if (!id.value || !name.value)
return;
this.attributes = <FormArray>this.form.get('attributes');
var newAttribute = this.fb.group({
attributeCategoryId: [id.value],
name: [name.value],
});
this.newlist.push({ name: [name.value].toString(), attributeCategoryId: [id.value].toString() });
this.attributes.push(newAttribute);
id.value = '';
name.value = '';
}
removeAttr(i: any) {
this.attributes.removeAt(i);
this.list2 = [];
this.newlist.splice(i, 1);
}
我添加变体的部分有效,它仍然有我用来尝试将添加到主要产品的属性复制到变体中的代码,我认为这有效,但就是无法获得访问值以显示它们,variations.attributes 对路径无效。
initVariation() {
let v = this.fb.group({
price: [''],
vattributes: this.attributes //COPIES main attributes
});
this.attributes.reset(); //Reset the main attributes as they now
return v; //belong to a variation
}
addNewVar() {
const control = <FormArray>this.form.controls['variations'];
control.push(this.initVariation());
}
向变体添加属性的部分不起作用,这是我在 component.ts
中遇到问题的地方addAttrRow() {
const control = <FormArray>this.form.controls['variations.vattributes']
control.push(this.initVattr())
}
initVattr() {
let va = this.fb.group({
vattributeCategoryId: [''],
vname: ['']
})
return va;
}
最后,我的 html 更乱了哈哈:
<h1>New Product</h1>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Product Name</label>
<div *ngIf="!form.get('name').valid" class="alert alert-danger">
{{ form.get('name').getError('remote') }}
</div>
<input [(ngModel)]="name" type="text" formControlName="name" class="form-control">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Price</label>
<div *ngIf="!form.get('price').valid" class="alert alert-danger">
{{ form.get('price').getError('remote') }}
</div>
<input [(ngModel)]="price" type="number" formControlName="price" class="form-control">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<label>Product Description</label>
<div *ngIf="!form.get('description').valid" class="alert alert-danger">
{{ form.get('description').getError('remote') }}
</div>
<textarea formControlName="description" class="form-control"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<div>
<h4>Attributes</h4>
<div class="form-inline" >
<div class="form-group">
<div formArrayName="attributes">
<select #ac name="attributeCategoryId">
<option value="" selected>Category</option>
<option *ngFor="let a of attriblist;let i = index" value="{{a.id}}">{{a.name}}</option>
</select>
<input #a name="name" placeholder="Attribute name" />
</div>
</div>
<button type="button" class="btn btn-default" (click)="addAttribute(ac,a)">Add Attribute</button>
</div>
<br>
<table class="table-bordered table table-striped">
<thead>
<tr>
<th>Attr. Category</th>
<th>Attr.</th>
<th><button type="button" (click)="addNewVar()" class="btn btn-primary">Add Variation</button></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let a of form.value.attributes; let i = index;" >
<td *ngIf="i > 0">{{a.attributeCategoryId}}</td>
<td *ngIf="i > 0">{{a.name}}</td>
<td *ngIf="i > 0"><button (click)="removeAttr(i)" class="btn btn-danger">X</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--Variations Start-->
<div class="row" formArrayName="variations">
<div *ngFor="let variation of form.controls.variations.controls; let i=index" [formGroupName]="i">
<h5>Variation #{{ i + 1 }}</h5>
<p></p>
<div class="form-group">
<label>Variation Price</label>
<input name="vprice" style="max-width:50px" class="form-control">
</div>
<table>
<thead>
<tr>
<th>Attr. Category</th>
<th>Attr.</th>
<th><button class="btn btn-success" (click)="addAttrRow()">+</button></th>
</tr>
</thead>
<tbody name="vattributes">
<tr *ngFor="let attribute of variation.get('vattributes'); let ii = index;">
<td><input type="text" name="vattributeCateforyId" /></td>
<td><input type="text" name="vname" /></td>
<td><button (click)="removeVAttr(ii)" class="btn btn-danger">X</button></td>
</tr>
</tbody>
</table>
<button class="btn btn-danger" (click)="removeVariation(i)">Delete</button>
</div>
</div>
<!--Variations End-->
<br>
<p>
<button type="submit" class="btn btn-primary">Save</button>
</p>
</form>
我看到你的代码中有很多错误。
例如
1) 你应该知道在处理从 FormArray
所以不用
const control = <FormArray>this.form.controls['variations.vattributes'];
我们应该使用
addAttrRow(index) {
const control = <FormArray>this.form.get(['variations', index, 'vattributes']);
2) 如果您没有为 button
指定类型,它将使用 submit
作为默认值。
<button class="btn btn-success" (click)="addAttrRow()">+</button>
这可能会导致不可预知的情况。
所以尝试指定 type="button"
3) 你遍历对象
*ngFor="let attribute of variation.get('vattributes');
而你需要遍历数组
*ngFor="let variation of form.controls.variations.controls;
我创建了 Plunker Example 可以帮助您意识到自己做错了什么