在Angular 7中,我有一个反应式表单,该表单用于创建和编辑现有对象。创建效果很好。
编辑时,API调用返回一个用于初始化FormGroup的对象。其中一些属性是下拉选择的结果。如何预先选择带有FormGroup数据的下拉菜单?
在示例中,我模拟了我们正在编辑的面板或订单项,它来自“服务器”,该面板具有承印物属性。可以将基材想像成汽车。为了准确了解汽车(Tundra SR5),您首先必须选择品牌(Toyota),然后选择饰件(SR5)。同样,基板具有两个定义属性,即尺寸(4x8)和厚度(0.75)。
所需的效果是,在加载表格时,下拉菜单应该已经具有正确的大小,厚度和在下拉菜单中选择的与基板在“服务器”上匹配的基材
我创建了带有功能简化版本的StackBlitz。
StackBlitz:https://stackblitz.com/edit/angular-sfusar
component.html
<form [formGroup]="panelForm" *ngIf="!loading">
<section class="form-block">
<div class="form-group">
<label for="select_size">Size</label>
<div class="select">
<select id="select_size" name="select_size" formControlName="size" (ngModelChange)="sizeChange($event)"
required>
<option *ngFor="let s of sizes" [ngValue]="s">{{ s.width }} x {{ s.height }}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="select_thickness">Thickness</label>
<div class="select">
<select id="select_thickness" name="select_thickness" formControlName="thickness" (ngModelChange)="thicknessChange($event)"
required>
<option *ngFor="let t of thicknesses" [ngValue]="t">{{t.value}}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="select_substrate">Material</label>
<div class="select">
<select id="select_substrate" name="select_substrate" formControlName="substrate"
required>
<option *ngFor="let s of substrates" [ngValue]="s">{{s.name}}</option>
</select>
</div>
</div>
</section>
</form>
component.ts
import { Component, OnInit } from '@angular/core';
import { OrderItem } from '../classes/order-item';
import { Size } from '../classes/size';
import { Thickness } from '../classes/thickness';
import { SubstrateService } from '../services/substrate.service';
import { OrderItemService } from '../services/order-item.service';
import { SizeService } from '../services/size.service';
import { ThicknessService } from '../services/thickness.service';
import { Substrate } from '../classes/substrate';
import {
FormGroup,
FormControl,
Validators,
FormArray,
FormBuilder
} from '@angular/forms';
@Component({
selector: 'app-order-item-form',
templateUrl: './order-item-form.component.html',
styleUrls: ['./order-item-form.component.scss']
})
export class OrderItemFormComponent implements OnInit {
panel: OrderItem;
panelId: number;
loading: boolean;
isEdit: boolean;
sizes = new Array<Size>();
thicknesses = new Array<Thickness>();
substrates = new Array<Substrate>();
selectedSize: Size;
selectedThickness: Thickness;
panelForm: FormGroup;
constructor(
private substrateService: SubstrateService,
private sizeService: SizeService,
private thicknessService: ThicknessService,
private orderItemService: OrderItemService,
private fb: FormBuilder
) {}
ngOnInit() {
this.loading = true;
// set this to === 1 to invoke the "Edit" panel form and isEdit === true
this.panelId = 1;
const sizePromise = this.sizeService.getList().toPromise();
const thicknessPromise = this.thicknessService.getList().toPromise();
Promise.all([
sizePromise,
thicknessPromise
]).then(response => {
this.sizes = response[0];
this.thicknesses = response[1];
this.isEdit = this.panel != null;
this.orderItemService.getSingle(this.panelId).subscribe(response => {
this.panel = response;
this.buildForms();
console.log(this.panel);
this.loading = false;
});
});
}
buildForms() {
this.panelForm = new FormGroup({
size: new FormControl(this.panel.substrate.size, Validators.required),
thickness: new FormControl(this.panel.substrate.thickness, Validators.required),
substrate: new FormControl(this.panel.substrate, Validators.required)
});
}
sizeChange(size: Size) {
if (size != null) {
this.selectedSize = size;
if (this.selectedThickness != null) {
this.getSubstrates();
}
} else {
this.selectedSize = null;
}
}
thicknessChange(thickness: Thickness) {
if (thickness != null) {
this.selectedThickness = thickness;
if (this.selectedSize != null) {
this.getSubstrates();
}
} else {
this.selectedThickness = null;
}
}
getSubstrates() {
this.substrateService.filter(this.selectedSize._id, this.selectedThickness._id)
.toPromise().then(response => {
this.substrates = response;
})
.catch();
}
get substrate() {
return this.panelForm.get('substrate').value as Substrate;
}
}
服务
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { Thickness } from '../classes/thickness';
import { Size } from '../classes/size';
import { Substrate } from '../classes/substrate';
import { OrderItem } from '../classes/order-item';
@Injectable({
providedIn: 'root'
})
export class ThicknessService {
thicknesses: Thickness[] = JSON.parse( `[{ "_id": 1, "value": 0.75 },
{ "_id": 2, "value": 1 },
{ "_id": 3, "value": 1.25 }]`);
public getList(): Observable<Thickness[]> {
return of(this.thicknesses);
}
}
@Injectable({
providedIn: 'root'
})
export class SizeService {
sizes: Size[] = JSON.parse( `[{ "_id": 1, "height": 8, "width": 4 },
{ "_id": 2, "height": 10, "width": 5 },
{ "_id": 3, "height": 12, "width": 5 }]`);
public getList(): Observable<Size[]> {
return of(this.sizes);
}
}
@Injectable({
providedIn: 'root'
})
export class SubstrateService {
substrates: Substrate[] = JSON.parse( `[{
"_id": 1,
"name": "MDF",
"size": { "_id": 1, "height": 8, "width": 4 },
"thickness": { "_id": 1, "value": 0.75 }
},
{
"_id": 2,
"name": "PB",
"size": { "_id": 2, "height": 10, "width": 5 },
"thickness": { "_id": 2, "value": 1 }
},
{
"_id": 3,
"name": "WB",
"size": { "_id": 3, "height": 12, "width": 5 },
"thickness": { "_id": 3, "value": 1.25 }
}
]`);
public filter(sizeId: number, thicknessId: number): Observable<Substrate[]> {
return of(this.substrates.filter(s => s.size._id === sizeId && s.thickness._id === thicknessId));
}
}
@Injectable({
providedIn: 'root'
})
export class OrderItemService {
orderItem: OrderItem = JSON.parse( `{ "substrate": {
"_id": 2,
"name": "PB",
"size": { "_id": 2, "height": 10, "width": 5 },
"thickness": { "_id": 2, "value": 1 }
} }`);
newItem = new OrderItem();
public getSingle(id: number): Observable<OrderItem> {
if (id === 1) return of(this.orderItem);
return of(this.newItem);
}
}
答案 0 :(得分:0)
Substrate
,Size
和Thickness
是类。这些类别的实例与的实例不同。 Substrate
中的OrderItem
。因此,当您像现在这样绑定[ngValue]
并在模型中设置表单值时,它们将不匹配。
我建议对代码进行以下更改以使其正常运行。该示例仅适用于Size
,但可以应用于所有三种类型:
<option *ngFor="let s of sizes" [ngValue]="s._id">{{ s.width }} x {{ s.height }}</option>
this.panelForm = new FormGroup({
size: new FormControl(this.panel.substrate.size._id, Validators.required),
});
当然,您以后需要时将_id
转换回一个对象(通过在sizes
数组中查找它)。