Angular/Reactive Forms - 添加或删除FormControl列表 - 绑定模板(附demo)
Angular/Reactive Forms - Add or Delete an list of FormControl - Binding template (With demo)
我有一个 matSelect
因为我可以 select 一个从 1 到 10 的数字,这取决于我必须用 *ngFor 显示相同数量的 matInput
。 select 中默认的数字 select 是 1(所以我们默认也有一个 matInput
)
<mat-form-field>
<mat-select placeholder="Number of winners to reward" [value]="selected" (selectionChange)="selectNumber($event)">
<mat-option *ngFor="let emailNumber of totalEmailsNumber" [value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
<div formArrayName="mails">
<mat-form-field *ngFor="let email of form.get('mails').controls; let i = index">
<textarea matInput [formControlName]="i"></textarea>
</mat-form-field>
</div>
添加第一个的默认 FormControl MatInput
我这样做:
this.form.controls['mails'] = this.fb.array(this.emailsNumber.map(() => new FormControl('', Validators.required)));
有效,但我无法管理添加另一个 FormControl
或删除它的逻辑,例如如果用户在 select 中选择 10 然后将其更改为 4,
并管理模板中的绑定。
我也想知道 *ngFor="let email of form.get('mails').controls
是个好习惯吗?
Here's a Minimal StackBlitz Demo to work with
我们可以使用简单的 for 循环,并为 FormArray 使用 push
或 removeAt
(获取索引)。不要尝试使用 splice
,它不会起作用 ;)
你也不想使用 (selectionChange)="selectNumber($event)"
因为那会被触发两次。而是使用 valueChange
:
<mat-form-field>
<mat-select (valueChange)="selectNumber($event)">
<mat-option *ngFor="let emailNumber of totalEmailsNumber" [value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
那么 selectNumber()
可能如下所示:
selectNumber(value) {
let formArr = this.form.get('mails') as FormArray;
// user has chosen less fields than already exists
if (formArr.controls.length > value) {
const toRemove = formArr.controls.length - value;
for (let i = 0; i < toRemove; i++ ) {
// remove last element
formArr.removeAt(formArr.length - 1);
}
} else {
const addFields = value - formArr.controls.length;
for (let i = 0; i < addFields; i++) {
formArr.push(new FormControl(''));
}
}
}
至于最后一个问题...
*ngFor="let email of form.get('mails').controls
非常好!我用那个,或者 getter.
试一试:
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
form: FormGroup;
totalEmailsNumber: number[];
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.totalEmailsNumber = this.createCustomLengthArray(10);
this.form = this.fb.group({
mails: this.fb.array([])
});
}
get mails() {
return (<FormArray>this.form.controls['mails']);
}
selectNumber(emailNumbers) {
const difference = this.mails.length - emailNumbers;
difference > 0 ? this.removeMails(difference) : this.addMails(difference);
}
removeMails(difference) {
this.createCustomLengthArray(difference)
.forEach(item => this.mails.removeAt(this.mails.length - 1));
}
addMails(difference) {
this.createCustomLengthArray(difference)
.forEach(
item => {
this.mails.push(this.fb.control(null, Validators.required));
}
);
}
createCustomLengthArray(length) {
return (new Array(Math.abs(length)))
.fill(null)
.map((item, index) => index + 1);
}
}
在模板中:
<form [formGroup]="form">
<mat-form-field>
<mat-select
placeholder="Number of winners to reward"
[value]="selected"
(selectionChange)="selectNumber($event.value)">
<mat-option
*ngFor="let emailNumber of totalEmailsNumber"
[value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
<div formArrayName="mails">
<mat-form-field
*ngFor="let email of form.controls['mails'].controls; let i = index">
<textarea
matInput
[formControlName]="i">
</textarea>
</mat-form-field>
</div>
</form>
Here's a Working Sample StackBlitz for your ref.
我有一个 matSelect
因为我可以 select 一个从 1 到 10 的数字,这取决于我必须用 *ngFor 显示相同数量的 matInput
。 select 中默认的数字 select 是 1(所以我们默认也有一个 matInput
)
<mat-form-field>
<mat-select placeholder="Number of winners to reward" [value]="selected" (selectionChange)="selectNumber($event)">
<mat-option *ngFor="let emailNumber of totalEmailsNumber" [value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
<div formArrayName="mails">
<mat-form-field *ngFor="let email of form.get('mails').controls; let i = index">
<textarea matInput [formControlName]="i"></textarea>
</mat-form-field>
</div>
添加第一个的默认 FormControl MatInput
我这样做:
this.form.controls['mails'] = this.fb.array(this.emailsNumber.map(() => new FormControl('', Validators.required)));
有效,但我无法管理添加另一个 FormControl
或删除它的逻辑,例如如果用户在 select 中选择 10 然后将其更改为 4,
并管理模板中的绑定。
我也想知道 *ngFor="let email of form.get('mails').controls
是个好习惯吗?
Here's a Minimal StackBlitz Demo to work with
我们可以使用简单的 for 循环,并为 FormArray 使用 push
或 removeAt
(获取索引)。不要尝试使用 splice
,它不会起作用 ;)
你也不想使用 (selectionChange)="selectNumber($event)"
因为那会被触发两次。而是使用 valueChange
:
<mat-form-field>
<mat-select (valueChange)="selectNumber($event)">
<mat-option *ngFor="let emailNumber of totalEmailsNumber" [value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
那么 selectNumber()
可能如下所示:
selectNumber(value) {
let formArr = this.form.get('mails') as FormArray;
// user has chosen less fields than already exists
if (formArr.controls.length > value) {
const toRemove = formArr.controls.length - value;
for (let i = 0; i < toRemove; i++ ) {
// remove last element
formArr.removeAt(formArr.length - 1);
}
} else {
const addFields = value - formArr.controls.length;
for (let i = 0; i < addFields; i++) {
formArr.push(new FormControl(''));
}
}
}
至于最后一个问题...
*ngFor="let email of form.get('mails').controls
非常好!我用那个,或者 getter.
试一试:
import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
form: FormGroup;
totalEmailsNumber: number[];
constructor(private fb: FormBuilder) {
}
ngOnInit() {
this.totalEmailsNumber = this.createCustomLengthArray(10);
this.form = this.fb.group({
mails: this.fb.array([])
});
}
get mails() {
return (<FormArray>this.form.controls['mails']);
}
selectNumber(emailNumbers) {
const difference = this.mails.length - emailNumbers;
difference > 0 ? this.removeMails(difference) : this.addMails(difference);
}
removeMails(difference) {
this.createCustomLengthArray(difference)
.forEach(item => this.mails.removeAt(this.mails.length - 1));
}
addMails(difference) {
this.createCustomLengthArray(difference)
.forEach(
item => {
this.mails.push(this.fb.control(null, Validators.required));
}
);
}
createCustomLengthArray(length) {
return (new Array(Math.abs(length)))
.fill(null)
.map((item, index) => index + 1);
}
}
在模板中:
<form [formGroup]="form">
<mat-form-field>
<mat-select
placeholder="Number of winners to reward"
[value]="selected"
(selectionChange)="selectNumber($event.value)">
<mat-option
*ngFor="let emailNumber of totalEmailsNumber"
[value]="emailNumber">
{{ emailNumber }}
</mat-option>
</mat-select>
</mat-form-field>
<div formArrayName="mails">
<mat-form-field
*ngFor="let email of form.controls['mails'].controls; let i = index">
<textarea
matInput
[formControlName]="i">
</textarea>
</mat-form-field>
</div>
</form>
Here's a Working Sample StackBlitz for your ref.