Angular 2でフォームを構築するためにテンプレート駆動型のアプローチを使用しており、テンプレートで使用できるカスタムバリデータを正常に作成しました。
ただし、特定のエラーにバインドされた特定のエラーメッセージを表示する方法が見つかりません。フォームが無効である理由を区別したいと思います。どうすれば達成できますか?
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Site } from './../site';
import { BackendService } from './../backend.service';
import { email } from './../validators';
import { CustomValidators } from './../validators';
@Component({
templateUrl: 'app/templates/form.component.html',
styleUrls: ['app/css/form.css'],
directives: [CustomValidators.Email, CustomValidators.Url, CustomValidators.Goof],
providers: [BackendService]
})
export class FormComponent {
active = true;
submitted = false;
model = new Site();
onSubmit() {
this.submitted = true;
console.log(this.model);
}
resetForm() {
this.model = new Site();
this.submitted = false;
this.active = false;
setTimeout(() => this.active = true, 0);
}
get diagnostics() {
return JSON.stringify(this.model)
}
}
import { Directive, forwardRef } from '@angular/core';
import { NG_VALIDATORS, FormControl } from '@angular/forms';
import { BackendService } from './backend.service';
function validateEmailFactory(backend:BackendService) {
return (c:FormControl) => {
let EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
return EMAIL_REGEXP.test(c.value) ? null : {
validateEmail: {
valid: false
}
};
};
}
export module CustomValidators {
@Directive({
selector: '[email][ngModel],[email][formControl]',
providers: [
{provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Email), multi: true}
]
})
export class Email {
validator:Function;
constructor(backend:BackendService) {
this.validator = validateEmailFactory(backend);
}
validate(c:FormControl) {
return this.validator(c);
}
}
@Directive({
selector: '[url][ngModel],[url][formControl]',
providers: [
{provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Url), multi: true}
]
})
export class Url {
validator:Function;
constructor(backend:BackendService) {
this.validator = validateEmailFactory(backend);
}
validate(c:FormControl) {
var pattern = /(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;
return pattern.test(c.value) ? null : {
validateEmail: {
valid: false
}
};
}
}
@Directive({
selector: '[goof][ngModel],[goof][formControl]',
providers: [
{provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Goof), multi: true}
]
})
export class Goof {
validate(c:FormControl) {
return {
validateGoof: {
valid: false
}
};
}
}
}
AbstractControl#hasError(...)
メソッドをチェックするだけで、コントロールに特定のエラーがあるかどうかを確認できます。 FormGroup
とFormControl
は両方ともAbstractControl
sです。 FormControl
の場合は、エラー名を引数として渡すだけです。例えば
function regexValidator(control: FormControl): {[key:string]: boolean} {
if (!control.value.match(/^pee/)) {
return { 'badName': true };
}
}
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
class="error">Name must start with <tt>pee</tt>.
</div>
バリデータメソッドは、キーがエラーの名前である文字列/ブールマップを返す必要があります。これは、hasError
メソッドで確認する名前です。
FormGroup
の場合、FormControl
へのパスを追加のパラメーターとして渡すことができます。
<div *ngIf="!form.valid && form.hasError('required', ['name'])"
class="error">Form name is required.</div>
name
は、単に入力のFormControl
の識別子です。
FormControl
とFormGroup
の両方のチェックの例を次に示します。
import { Component } from '@angular/core';
import {
FormGroup,
FormBuilder,
FormControl,
Validators,
AbstractControl,
REACTIVE_FORM_DIRECTIVES
} from '@angular/forms';
function regexValidator(control: FormControl): {[key:string]: boolean} {
if (!control.value.match(/^pee/)) {
return { 'badName': true };
}
}
@Component({
selector: 'validation-errors-demo',
template: `
<div>
<h2>Differentiate Validation Errors</h2>
<h4>Type in "peeskillet"</h4>
<form [formGroup]="form">
<label for="name">Name: </label>
<input type="text" [formControl]="nameCtrl"/>
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('required')"
class="error">Name is required.</div>
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
class="error">Name must start with <tt>pee</tt>.</div>
<div *ngIf="!form.valid && form.hasError('required', ['name'])"
class="error">Form name is required.</div>
</form>
</div>
`,
styles: [`
.error {
border-radius: 3px;
border: 1px solid #AB4F5B;
color: #AB4F5B;
background-color: #F7CBD1;
margin: 5px;
padding: 10px;
}
`],
directives: [REACTIVE_FORM_DIRECTIVES],
providers: [FormBuilder]
})
export class ValidationErrorsDemoComponent {
form: FormGroup;
nameCtrl: AbstractControl;
constructor(formBuilder: FormBuilder) {
let name = new FormControl('', Validators.compose([
Validators.required, regexValidator
]));
this.form = formBuilder.group({
name: name
});
this.nameCtrl = this.form.controls['name'];
}
}
わかりましたので、私はそれを動作させましたが、それは少し冗長です。入力の個々のFormControl
に適切にアクセスする方法を理解できませんでした。だから私はただFormGroup
への参照を作成しました
<form #f="ngForm" novalidate>
次に、有効性を確認するために、フォームコントロール名のパスを渡したhasError
オーバーロードを使用します。ために <input>
name
とngModel
を使用する場合、name
の値は、その名前をFormGroup
名としてメインFormControl
に追加されます。だからあなたはそれにアクセスすることができます
`f.form.hasError('require', ['nameCtrl'])`
name=nameCtrl
。 f.form
。 f
は、NgForm
メンバー変数FormGroup
を持つform
インスタンスです。
以下はリファクタリングされた例です
import { Component, Directive } from '@angular/core';
import {
FormControl,
Validators,
AbstractControl,
NG_VALIDATORS,
REACTIVE_FORM_DIRECTIVES
} from '@angular/forms';
function validateRegex(control: FormControl): {[key:string]: boolean} {
if (!control.value || !control.value.match(/^pee/)) {
return { 'badName': true };
}
}
@Directive({
selector: '[validateRegex]',
providers: [
{ provide: NG_VALIDATORS, useValue: validateRegex, multi: true }
]
})
export class RegexValidator {
}
@Component({
moduleId: module.id,
selector: 'validation-errors-template-demo',
template: `
<div>
<h2>Differentiate Validation Errors</h2>
<h4>Type in "peeskillet"</h4>
<form #f="ngForm" novalidate>
<label for="name">Name: </label>
<input type="text" name="nameCtrl" ngModel validateRegex required />
<div *ngIf="!f.form.valid && f.form.hasError('badName', ['nameCtrl'])"
class="error">Name must start with <tt>pee</tt>.</div>
<div *ngIf="!f.form.valid && f.form.hasError('required', ['nameCtrl'])"
class="error">Name is required.</div>
</form>
</div>
`,
styles: [`
.error {
border-radius: 3px;
border: 1px solid #AB4F5B;
color: #AB4F5B;
background-color: #F7CBD1;
margin: 5px;
padding: 10px;
}
`],
directives: [REACTIVE_FORM_DIRECTIVES, RegexValidator]
})
export class ValidationErrorsTemplateDemoComponent {
}
Angularでこの問題に取り組むために、AngularJsのng-messages
に似た一連のディレクティブを作成しました。 https://github.com/DmitryEfimenko/ngx-messages
<div [val-messages]="myForm.get('email')">
<span val-message="required">Please provide email address</span>
<span val-message="server" useErrorValue="true"></span>
</div>