Angular 6 种反应形式。 select 的 FormArray
Angular 6 reactive forms. FormArray of select
我关注了 Angular Reative Form guide,它解释了如何将地址的 FormArray 添加到 FormGroup。
现在我想要一个可以拥有不同能力的英雄,从 select
中选择它们,或者更好地从 select
的动态数组中选择。
从 Angular 文档的示例传递到我想要的功能,但我无法实现 运行。
这是我的英雄-form.ts
@Component({
selector: 'app-hero-form',
templateUrl: './hero-form.component.html',
styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent implements OnInit, OnChanges {
heroForm: FormGroup;
nameChangeLog: string[] = [];
hero: Hero = new Hero();
allPowers: Power[] = [];
constructor(private fb: FormBuilder, private powerService: PowerService) {
this.createForm();
this.logNameChange();
}
ngOnInit() {
this.powerService.getAll().subscribe(powers => this.allPowers = powers);
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required],
powers: this.fb.array([]),
});
}
ngOnChanges() {
this.rebuildForm();
}
rebuildForm() {
this.heroForm.reset({
name: this.hero.name
});
this.setPowersControl(this.hero.powers);
}
setPowersControl(powers: Power[]) {
const powersFGs = powers.map(pow => this.fb.group(pow));
const powersFormArray = this.fb.array(powersFGs);
this.heroForm.setControl('powers', powersFormArray);
}
get powers(): FormArray {
const pows = this.heroForm.get('powers') as FormArray;
return pows;
}
addPowerChoice() {
this.powers.push(this.fb.control(new Power()));
// this.powers.push(this.fb.group(new Power(), Validators.required));
}
onSubmit() {
this.hero = this.prepareSaveHero();
console.log('SAVING HERO', this.hero);
// this.heroService.updateHero(this.hero).subscribe(/* error handling */);
this.rebuildForm();
}
prepareSaveHero(): Hero {
const formModel = this.heroForm.value;
// deep copy of form model lairs
const powersDeepCopy: Power[] = formModel.powers.map(
(pow: Power) => Object.assign({}, pow)
);
// return new `Hero` object containing a combination of original hero value(s)
// and deep copies of changed form model values
const saveHero: Hero = {
id: this.hero.id,
name: formModel.name as string,
// addresses: formModel.secretLairs // <-- bad!
powers: powersDeepCopy
};
return saveHero;
}
revert() { this.rebuildForm(); }
logNameChange() {
const nameControl = this.heroForm.get('name');
nameControl.valueChanges.forEach(
(value: string) => this.nameChangeLog.push(value)
);
}
}
这是我的英雄-form.html
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
<div style="margin-bottom: 1em">
<button type="submit" [disabled]="heroForm.pristine" class="btn btn-success">Save
</button>
<button type="button" (click)="revert()" [disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
</div>
<!-- Hero Detail Controls -->
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formArrayName="powers" class="well well-lg">
<div *ngFor="let pow of powers.controls; let i=index" [formControlName]="i">
<!-- The repeated power template -->
<h4>Potere #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Power:
<select class="form-control">
<option *ngFor="let pow of allPowers" [value]="pow">{{pow.name}}</option>
</select>
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
</div>
<button (click)="addPowerChoice()" type="button">Add a Power</button>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>
<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>
这是仅返回存根数据的电源服务
@Injectable({
providedIn: 'root'
})
export class PowerService {
constructor() {
}
getAll(): Observable<Power[]> {
return of(this.getProds());
}
getProds(): Power[] {
const powers = [];
for (let i = 0; i < 10; i++) {
const pow = new Power();
pow.id = i+'';
pow.name = 'Power ' + i;
powers.push(pow);
}
return powers;
}
}
这些是我的数据模型
export class Hero {
id: number;
name: string;
powers: Power[];
}
export class Power {
id: string = '';
name: string = '';
}
这里我做了一个stackblitz example但是没用
我解决了
我已按照 Lucas Klaassen 的建议将 formControlName
从 div
移动到 select
,并将 [value]
更改为 [ngValue]
到 option
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
<div style="margin-bottom: 1em">
<button type="submit"
[disabled]="heroForm.pristine" class="btn btn-success">Save
</button>
<button type="button" (click)="revert()"
[disabled]="heroForm.pristine" class="btn btn-danger">Revert
</button>
</div>
<!-- Hero Detail Controls -->
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formArrayName="powers" class="well well-lg">
<div *ngFor="let pow of powers.controls; let i=index">
<!-- The repeated power template -->
<h4>Potere #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Power:
<select class="form-control" [formControlName]="i">
<option *ngFor="let pow of allPowers" [ngValue]="pow">{{pow.name}}</option>
</select>
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
</div>
<button (click)="addPowerChoice()" type="button">Add a Power</button>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>
<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>
然后我改变了onSubmit()
添加了一个英雄的构造函数调用如下
onSubmit() {
this.hero = this.prepareSaveHero();
console.log('SAVING HERO', this.hero);
// this.heroService.updateHero(this.hero).subscribe(/* error handling */);
this.hero = new Hero();
this.rebuildForm();
}
然后我添加了一个自定义构造函数到 Hero
class
export class Hero {
id: number;
name: string;
powers: Power[];
constructor() {
this.id = 0;
this.name = '';
this.powers = [];
}
}
现在可以正常工作并在提交后正确重建表单
我关注了 Angular Reative Form guide,它解释了如何将地址的 FormArray 添加到 FormGroup。
现在我想要一个可以拥有不同能力的英雄,从 select
中选择它们,或者更好地从 select
的动态数组中选择。
从 Angular 文档的示例传递到我想要的功能,但我无法实现 运行。
这是我的英雄-form.ts
@Component({
selector: 'app-hero-form',
templateUrl: './hero-form.component.html',
styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent implements OnInit, OnChanges {
heroForm: FormGroup;
nameChangeLog: string[] = [];
hero: Hero = new Hero();
allPowers: Power[] = [];
constructor(private fb: FormBuilder, private powerService: PowerService) {
this.createForm();
this.logNameChange();
}
ngOnInit() {
this.powerService.getAll().subscribe(powers => this.allPowers = powers);
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required],
powers: this.fb.array([]),
});
}
ngOnChanges() {
this.rebuildForm();
}
rebuildForm() {
this.heroForm.reset({
name: this.hero.name
});
this.setPowersControl(this.hero.powers);
}
setPowersControl(powers: Power[]) {
const powersFGs = powers.map(pow => this.fb.group(pow));
const powersFormArray = this.fb.array(powersFGs);
this.heroForm.setControl('powers', powersFormArray);
}
get powers(): FormArray {
const pows = this.heroForm.get('powers') as FormArray;
return pows;
}
addPowerChoice() {
this.powers.push(this.fb.control(new Power()));
// this.powers.push(this.fb.group(new Power(), Validators.required));
}
onSubmit() {
this.hero = this.prepareSaveHero();
console.log('SAVING HERO', this.hero);
// this.heroService.updateHero(this.hero).subscribe(/* error handling */);
this.rebuildForm();
}
prepareSaveHero(): Hero {
const formModel = this.heroForm.value;
// deep copy of form model lairs
const powersDeepCopy: Power[] = formModel.powers.map(
(pow: Power) => Object.assign({}, pow)
);
// return new `Hero` object containing a combination of original hero value(s)
// and deep copies of changed form model values
const saveHero: Hero = {
id: this.hero.id,
name: formModel.name as string,
// addresses: formModel.secretLairs // <-- bad!
powers: powersDeepCopy
};
return saveHero;
}
revert() { this.rebuildForm(); }
logNameChange() {
const nameControl = this.heroForm.get('name');
nameControl.valueChanges.forEach(
(value: string) => this.nameChangeLog.push(value)
);
}
}
这是我的英雄-form.html
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
<div style="margin-bottom: 1em">
<button type="submit" [disabled]="heroForm.pristine" class="btn btn-success">Save
</button>
<button type="button" (click)="revert()" [disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
</div>
<!-- Hero Detail Controls -->
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formArrayName="powers" class="well well-lg">
<div *ngFor="let pow of powers.controls; let i=index" [formControlName]="i">
<!-- The repeated power template -->
<h4>Potere #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Power:
<select class="form-control">
<option *ngFor="let pow of allPowers" [value]="pow">{{pow.name}}</option>
</select>
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
</div>
<button (click)="addPowerChoice()" type="button">Add a Power</button>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>
<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>
这是仅返回存根数据的电源服务
@Injectable({
providedIn: 'root'
})
export class PowerService {
constructor() {
}
getAll(): Observable<Power[]> {
return of(this.getProds());
}
getProds(): Power[] {
const powers = [];
for (let i = 0; i < 10; i++) {
const pow = new Power();
pow.id = i+'';
pow.name = 'Power ' + i;
powers.push(pow);
}
return powers;
}
}
这些是我的数据模型
export class Hero {
id: number;
name: string;
powers: Power[];
}
export class Power {
id: string = '';
name: string = '';
}
这里我做了一个stackblitz example但是没用
我解决了
我已按照 Lucas Klaassen 的建议将 formControlName
从 div
移动到 select
,并将 [value]
更改为 [ngValue]
到 option
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
<div style="margin-bottom: 1em">
<button type="submit"
[disabled]="heroForm.pristine" class="btn btn-success">Save
</button>
<button type="button" (click)="revert()"
[disabled]="heroForm.pristine" class="btn btn-danger">Revert
</button>
</div>
<!-- Hero Detail Controls -->
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formArrayName="powers" class="well well-lg">
<div *ngFor="let pow of powers.controls; let i=index">
<!-- The repeated power template -->
<h4>Potere #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Power:
<select class="form-control" [formControlName]="i">
<option *ngFor="let pow of allPowers" [ngValue]="pow">{{pow.name}}</option>
</select>
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
</div>
<button (click)="addPowerChoice()" type="button">Add a Power</button>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>
<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>
然后我改变了onSubmit()
添加了一个英雄的构造函数调用如下
onSubmit() {
this.hero = this.prepareSaveHero();
console.log('SAVING HERO', this.hero);
// this.heroService.updateHero(this.hero).subscribe(/* error handling */);
this.hero = new Hero();
this.rebuildForm();
}
然后我添加了一个自定义构造函数到 Hero
class
export class Hero {
id: number;
name: string;
powers: Power[];
constructor() {
this.id = 0;
this.name = '';
this.powers = [];
}
}
现在可以正常工作并在提交后正确重建表单