フォームのtextarea
を動的に作成する必要があります。私は次のモデルを持っています:
this.fields = {
isRequired: true,
type: {
options: [
{
label: 'Option 1',
value: '1'
},
{
label: 'Option 2',
value: '2'
}
]
}
};
そしてフォーム:
this.userForm = this.fb.group({
isRequired: [this.fields.isRequired, Validators.required],
//... here a lot of other controls
type: this.fb.group({
options: this.fb.array(this.fields.type.options),
})
});
テンプレートの一部:
<div formGroupName="type">
<div formArrayName="options">
<div *ngFor="let option of userForm.controls.type.controls.options.controls; let i=index">
<textarea [formControlName]="i"></textarea>
</div>
</div>
</div>
ご覧のとおり、オブジェクトの配列があり、label
プロパティを使用してtextarea
で表示したいと思います。わかりました [object Object]
。 options
を次のような単純な文字列配列に変更した場合:['Option 1', 'Option 2']
、その後、すべて正常に動作します。しかし、オブジェクトを使用する必要があります。したがって、代わりに:
<textarea [formControlName]="i"></textarea>
私が試してみました:
<textarea [formControlName]="option[i].label"></textarea>
しかし、それは機能しません。
オブジェクトの配列を使用するにはどうすればよいですか?
これは Plunkr です
label
とvalue
を含むFormGroupを追加する必要があります。これは、フォームによって作成されたオブジェクトがfields
オブジェクトと同じビルドであることも意味します。
ngOnInit() {
// build form
this.userForm = this.fb.group({
type: this.fb.group({
options: this.fb.array([]) // create empty form array
})
});
// patch the values from your object
this.patch();
}
その後、OnInitで呼び出されたメソッドで値にパッチを適用します。
patch() {
const control = <FormArray>this.userForm.get('type.options');
this.fields.type.options.forEach(x => {
control.Push(this.patchValues(x.label, x.value))
});
}
// assign the values
patchValues(label, value) {
return this.fb.group({
label: [label],
value: [value]
})
}
最後に、ここに
AJT_82からの回答は私にとってとても役に立ちました。彼のコードを再利用し、同様の例を構築する方法を共有すると思いました-一度にサインアップするために複数の人を招待するより一般的なユースケースがあるかもしれませんこのような: -
これは他の人にも役立つかもしれないと思ったので、ここに追加します。
フォームは、電子メール用のテキスト入力の単純な配列であり、それぞれにカスタムバリデータがロードされていることがわかります。スクリーンショットでJSON構造を確認できます-テンプレートのpre行(AJTに感謝)を参照してください。これは、モデルとコントロールが接続されているかどうかを確認するための開発中に非常に便利なアイデアです。
したがって、まず、必要なオブジェクトを宣言します。 3つの空の文字列がモデルデータであることに注意してください(テキスト入力にバインドします)。
public form: FormGroup;
private control: FormArray;
private emailsModel = { emails: ['','','']} // the model, ready to hold the emails
private fb : FormBuilder;
コンストラクターはクリーンです(テストを簡単にするために、送信後にフォームデータを送信するためにuserServiceを挿入するだけです)。
constructor(
private _userService: UserService,
) {}
フォームはemailsArray
コントロール自体への参照を保存するなど、initメソッドに組み込まれているため、後でその子(実際の入力)がタッチされているかどうかを確認できます。
ngOnInit() {
this.fb = new FormBuilder;
this.form = this.fb.group({
emailsArray: this.fb.array([])
});
this.control = <FormArray>this.form.controls['emailsArray'];
this.patch();
}
private patch(): void {
// iterate the object model and extra values, binding them to the controls
this.emailsModel.emails.forEach((item) => {
this.control.Push(this.patchValues(item));
})
}
これは、バリデーターで(AbstracControl型の)各入力コントロールを構築するものです。
private patchValues(item): AbstractControl {
return this.fb.group({
email: [item, Validators.compose([emailValidator])]
})
}
入力がタッチされたかどうか、およびバリデーターがエラーを発生させたかどうかを確認する2つのヘルパーメソッド(テンプレートの使用方法を確認するには、テンプレートの*ngFor
から配列のインデックス値を渡します):
private hasError(i):boolean {
// const control = <FormArray>this.form.controls['emailsArray'];
return this.control.controls[i].get('email').hasError('invalidEmail');
}
private isTouched(i):boolean {
// const control = <FormArray>this.form.controls['emailsArray'];
return this.control.controls[i].get('email').touched;
}
検証ツールは次のとおりです。
export function emailValidator(control: FormControl): { [key: string]: any } {
var emailRegexp = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$/;
if (control.value && !emailRegexp.test(control.value)) {
return { invalidEmail: true };
}
}
そしてテンプレート:
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" class="text-left">
<div formArrayName="emailsArray">
<div *ngFor="let child of form.controls.emailsArray.controls; let i=index">
<div class="form-group" formGroupName="{{i}}">
<input formControlName="email"
class="form-control checking-field"
placeholder="Email" type="text">
<span class="help-block" *ngIf="isTouched(i)">
<span class="text-danger"
*ngIf="hasError(i)">Invalid email address
</span>
</span>
</div>
</div>
</div>
<pre>{{form.value | json }}</pre>
<div class="form-group text-center">
<button class="btn btn-main btn-block" type="submit">INVITE</button>
</div>
</form>
価値のあることのために、私はこのひどい混乱から始めました-しかし、下のコードを見ると、上のコードをもっと簡単に理解できるかもしれません!
public form: FormGroup;
public email1: AbstractControl;
public email2: AbstractControl;
public email3: AbstractControl;
public email4: AbstractControl;
public email5: AbstractControl;
constructor(
fb: FormBuilder
) {
this.form = fb.group({
'email1': ['', Validators.compose([emailValidator])],
'email2': ['', Validators.compose([emailValidator])],
'email3': ['', Validators.compose([emailValidator])],
'email4': ['', Validators.compose([emailValidator])],
'email5': ['', Validators.compose([emailValidator])],
});
this.email1 = this.form.controls['email1'];
this.email2 = this.form.controls['email2'];
this.email3 = this.form.controls['email3'];
this.email4 = this.form.controls['email4'];
this.email5 = this.form.controls['email5'];
}
上記はテンプレートでこれらのdivのうち5つを使用しました-非常に乾燥していません!
<div class="form-group">
<input [formControl]="email1" class="form-control checking-field" placeholder="Email" type="text">
<span class="help-block" *ngIf="form.get('email1').touched">
<span class="text-danger" *ngIf="form.get('email1').hasError('invalidEmail')">Invalid email address</span>
</span>
</div>
FormControlName
では不可能だと思います。
ngModel
を使用できます。変更したプランカーを見てください。
http://plnkr.co/edit/0DXSIUY22D6Qlvv0HF0D?p=preview
@Component({
selector: 'my-app',
template: `
<hr>
<form [formGroup]="userForm" (ngSubmit)="submit(userForm.value)">
<input type="checkbox" formControlName="isRequired"> Required Field
<div formGroupName="type">
<div formArrayName="options">
<div *ngFor="let option of userForm.controls.type.controls.options.controls; let i=index">
<label>{{ option.value.label }}</label><br />
<!-- change your textarea -->
<textarea [name]="i" [(ngModel)]="option.value.value" [ngModelOptions]="{standalone: true}" ></textarea>
</div>
</div>
</div>
<button type="submit">Submit</button>
</form>
<br>
<pre>{{userForm.value | json }}</pre>
`,
})
export class App {
name:string;
userForm: FormGroup;
fields:any;
ngOnInit() {
this.fields = {
isRequired: true,
type: {
options: [
{
label: 'Option 1',
value: '1'
},
{
label: 'Option 2',
value: '2'
}
]
}
};
this.userForm = this.fb.group({
isRequired: [this.fields.isRequired, Validators.required],
//... here a lot of other controls
type: this.fb.group({
// .. added map-function
options: this.fb.array(this.fields.type.options.map(o => new FormControl(o))),
})
});
}
submit(value) {
console.log(value);
}
constructor(private fb: FormBuilder) { }
addNumber() {
const control = <FormArray>this.userForm.controls['numbers'];
control.Push(new FormControl())
}
}