Angularで「Expected validator to return Promise or Observable」エラーが発生した時の解決方法
JavaScript、Angular、Angular5 における「Expected validator to return Promise or Observable」エラー
Angularフォームバリデーションにおいて、asyncValidators
で非同期処理を行う場合、Promise
または Observable
を返す必要があります。これが満たされない場合、「Expected validator to return Promise or Observable」というエラーが発生します。
原因
このエラーは以下の理由で発生します。
asyncValidators
で返された値がPromise
またはObservable
ではないasyncValidators
関数内でエラーが発生している
解決方法
このエラーを解決するには、以下のいずれかの方法を試します。
asyncValidators
は、Promise
または Observable
を返す関数です。これらのいずれかを返していない場合は、適切な型に変換する必要があります。
例:Promise を返す場合
asyncValidators: {
userName: (control: FormControl) => Promise<ValidationErrors | null> {
return new Promise((resolve) => {
// 非同期処理
setTimeout(() => {
if (control.value === 'invalid') {
resolve({
userName: 'ユーザー名が不正です'
});
} else {
resolve(null);
}
}, 1000);
});
}
}
例:Observable を返す場合
asyncValidators: {
userName: (control: FormControl) => Observable<ValidationErrors | null> {
return new Observable((observer) => {
// 非同期処理
setTimeout(() => {
if (control.value === 'invalid') {
observer.next({
userName: 'ユーザー名が不正です'
});
} else {
observer.next(null);
}
}, 1000);
});
}
}
asyncValidators
関数内でエラーが発生している場合、エラー内容を確認して修正する必要があります。
エラー内容の確認方法
ブラウザの開発者ツールを使用して、コンソールログを確認します。コンソールログには、エラーメッセージとエラーが発生した箇所が表示されます。
エラーの修正例
asyncValidators: {
userName: (control: FormControl) => Promise<ValidationErrors | null> {
return new Promise((resolve) => {
// 非同期処理
setTimeout(() => {
// ここでエラーが発生
if (control.value === undefined) {
resolve({
userName: 'ユーザー名が未入力です'
});
} else {
resolve(null);
}
}, 1000);
});
}
}
上記の例では、control.value
が undefined
の場合にエラーが発生しています。このエラーを修正するには、undefined
の場合も適切な処理を行うようにコードを変更する必要があります。
上記以外にも、このエラーを解決するための方法はいくつか考えられます。詳細については、Angular ドキュメントや関連資料を参照してください。
app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators, AsyncValidatorFn } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
form: FormGroup;
constructor() { }
ngOnInit() {
this.form = new FormGroup({
userName: new FormControl('', [
Validators.required,
this.userNameAsyncValidator()
])
});
}
userNameAsyncValidator(): AsyncValidatorFn {
return (control: FormControl) => new Promise((resolve) => {
// 非同期処理
setTimeout(() => {
if (control.value === 'invalid') {
resolve({
userName: 'ユーザー名が不正です'
});
} else {
resolve(null);
}
}, 1000);
});
}
}
<form [formGroup]="form">
<input type="text" formControlName="userName" />
<button type="submit">送信</button>
</form>
このコードを実行すると、ユーザー名が "invalid" の場合、「ユーザー名が不正です」というエラーメッセージが表示されます。
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators, AsyncValidatorFn } from '@angular/forms';
import { Observable } from 'rxjs';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
form: FormGroup;
constructor() { }
ngOnInit() {
this.form = new FormGroup({
userName: new FormControl('', [
Validators.required,
this.userNameAsyncValidator()
])
});
}
userNameAsyncValidator(): AsyncValidatorFn {
return (control: FormControl) => new Observable((observer) => {
// 非同期処理
setTimeout(() => {
if (control.value === 'invalid') {
observer.next({
userName: 'ユーザー名が不正です'
});
} else {
observer.next(null);
}
}, 1000);
});
}
}
上記のコードは、Promise
の代わりに Observable
を使用しています。
「Expected validator to return Promise or Observable」エラーを解決する他の方法
asyncValidators
関数内で async
キーワードを使用すると、自動的に Promise
が返されます。
例:
asyncValidators: {
userName: (control: FormControl) => async () => {
// 非同期処理
const response = await fetch('https://api.example.com/users/' + control.value);
const data = await response.json();
if (data.valid === false) {
return {
userName: 'ユーザー名が不正です'
};
}
return null;
}
}
from
関数は、Observable
を生成する関数です。asyncValidators
関数内で from
を使用すると、Observable
を返すことができます。
asyncValidators: {
userName: (control: FormControl) => Observable<ValidationErrors | null> {
return from(fetch('https://api.example.com/users/' + control.value)).pipe(
map((response) => response.json()),
map((data) => {
if (data.valid === false) {
return {
userName: 'ユーザー名が不正です'
};
}
return null;
})
);
}
}
サードパーティライブラリを使用する
ngx-formly
などのサードパーティライブラリを使用すると、asyncValidators
をより簡単に記述することができます。
import { FormlyFieldConfig } from 'ngx-formly';
const fields: FormlyFieldConfig[] = [
{
key: 'userName',
type: 'input',
validators: {
asyncValidators: {
userName: (control: FormControl) => {
return this.userService.validateUserName(control.value);
}
}
}
}
];
javascript angular angular5