見上げてやりたいことをやろうとして困っています。
各行に入力があるテーブルがあり、ngForを使用して作成された各行をフォームグループと見なしたいと思います。
各フォームグループ内で、行内のコントロールのいずれかが入力されている場合、送信を行う前にフォームグループ全体を入力する必要があるという検証が必要です。
これが私のテンプレートにこれまでにあるものです。
Angular.ioを使用して数時間検索しても、必要なものに近いものが何も表示されないため、コンポーネントにはまだ何もありません。
<form>
<table id="table" class="mdl-data-table mdl-js-data-table mdl-data-table mdl-shadow--2dp">
<thead>
<tr>
<th>Day</th>
<th>Description</th>
<th>Open Time</th>
<th>Close Time</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let scheduleDetail of scheduleDetails">
<td style="padding: 0 8px 0 8px;">{{weekdayConverter(scheduleDetail.dayId)}}</td>
<td class="pad-input">
<mdl-textfield style="max-width:100px;" type="text" class="font" name="description" [(ngModel)]="scheduleDetail.description"></mdl-textfield>
</td>
<td>
<mdl-textfield style="max-width:75px" type="text" error-msg="hh:mm" name="openTime" pattern="([01]\d|2[0-3]):?([0-5]\d)" [(ngModel)]="scheduleDetail.openTime"></mdl-textfield>
</td>
<td>
<mdl-textfield style="max-width:75px" type="text" error-msg="hh:mm" name="closeTime" pattern="([01]\d|2[0-3]):?([0-5]\d)" [(ngModel)]="scheduleDetail.closeTime"></mdl-textfield>
</td>
</tr>
</tbody>
</table>
</form>
テンプレートに以下を追加しました。
入力を次のように変更しました:
<mdl-textfield (keyup)="formChange(scheduleDetail)" style="max-width:100px;" type="text" class="font" name="description" [(ngModel)]="scheduleDetail.description"></mdl-textfield>
コンポーネントに以下を追加しました。
formChange(detail:scheduleDetail){
if(this.checkValid(detail)==false)
this.scheduleDetails.filter(detail => detail == detail)[0].require=true;
else
this.scheduleDetails.filter(detail => detail == detail)[0].require=false;
this.checkForm();
}
checkValid(detail:scheduleDetail){
if(detail.description!=null && detail.description!=""){
if(this.checkTime(detail))
return true
else
return false
}
else
return true
}
checkTime(detail:scheduleDetail){
if(
(detail.openTime!=null && detail.closeTime!=null) &&
( detail.openTime!="" && detail.closeTime!="") &&
(this.checkRegExp(detail.openTime) && this.checkRegExp(detail.closeTime))
){
return true
}
else if((this.checkRegExp(detail.openTime) && this.checkRegExp(detail.closeTime))){
return true
}
else return false
}
checkRegExp(time:string){
let timeRegExp = /([01]\d|2[0-3]):?([0-5]\d)/;
if(timeRegExp.test(time)){
return true;
}
else
return false;
}
checkForm(){
let valid: boolean = true;
this.scheduleDetails.forEach(detail => {
if(detail.require==true){
valid = false;
}
});
this.scheduleDetails.forEach(detail => {
if(detail.description=="" || detail.description==null){
valid = false;
}
});
this.formValid = valid;
}
スケーリングや保守が難しいテンプレート駆動型フォームを使用しています。
ここでは、モデル駆動型フォームに移行する方法を説明します。
export class WeekScheduleComponent {
// Our empty Form
myForm: FormGroup;
constructor(private fb: FormBuilder){
// We inject FormBuilder to our component
// Now, we instantiate myForm with FormBuilder
// Notice that myForm is a FormGroup which contains an empty FormArray
this.myForm = this.fb.group({
scheduleDetail: this.fb.array([])
})
}
addRow(){
// This function instantiates a FormGroup for each day
// and pushes it to our FormArray
// We get our FormArray
const control = <FormArray>this.myForm.controls['scheduleDetail'];
// instantiate a new day FormGroup;
newDayGroup: FormGroup = this.initItems();
// Add it to our formArray
control.Push(newDayGroup);
}
initItems(): FormGroup{
// Here, we make the form for each day
return this.fb.group({
description: [null, Validators.required],
openTime: [null, Validators.required],
closeTime: [null, Validators.required]
});
}
submit(){
// do stuff and submit result
console.log(this.myForm.value);
}
}
<form [formGroup]="myForm" *ngIf="myForm">
<table formArrayName="scheduleDetail">
<tr *ngFor="let item of myForm.controls.scheduleDetail.controls; let i=index"
[formGroupName]="i" >
<td><input type='text' formControlName="description"></td>
<td><input type='text' formControlName="openTime"></td>
<td><input type='text' formControlName="closeTime"></td>
</tr>
</table>
</form>
<button (click)="addRow()">Add new item</button>
<button (click)="submit()" [disabled]="!myForm.valid">Submit</button>
成分
import { Component, OnInit } from '@angular/core';
import {FormGroup, FormBuilder, FormControl, Validators, FormArray} from '@angular/forms';
@Component({
selector: 'app-sales',
templateUrl: './sales.component.html',
styleUrls: ['./sales.component.css']
})
export class SalesComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder){
}
// getter to get a reference to scheduleDetail form array in myForm form group
get scheduleDetail():FormArray{
return <FormArray>this.myForm.get('scheduleDetail')
}
// add a new row, get reference to form array using getter method and Push form group into it
addRow(){
this.scheduleDetail.Push(this.initItems());
}
// make a form for each row!
initItems(): FormGroup{
return this.fb.group({
description: [null, Validators.required],
openTime: [null, Validators.required],
closeTime: [null, Validators.required]
});
}
submit(){
console.log(this.myForm.value)
}
ngOnInit() {
this.myForm = this.fb.group({
scheduleDetail: this.fb.array([this.initItems()])
})
}
}
テンプレート
<form [formGroup]="myForm" *ngIf="myForm">
<table formArrayName="scheduleDetail">
<thead>
<tr>
<th >Desc</th>
<th >Open Time</th>
<th >Close Time</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of myForm.controls.scheduleDetail.controls; let i=index"
[formGroupName]="i" >
<td><input type='text' formControlName="description"></td>
<td><input type='text' formControlName="openTime"></td>
<td><input type='text' formControlName="closeTime"></td>
</tr>
</tbody>
</table>
</form>
<button (click)="addRow()">Add new item</button>
<button (click)="submit()" [disabled]="!myForm.valid">Submit</button>