Angular 8 アプリケーションを開発しています。NgRx ストアを使用してフォーム エラーを表示し、カスタム非同期バリデーターを使用してリアクティブ フォームを表示したいと考えています。
login.component.ts
@Component({
selector: 'auth-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
})
export class LoginComponent implements OnInit {
public transitionController: TransitionController = new TransitionController(
true,
);
public form: FormGroup;
public pageState$: Observable<ILoginPageState>;
public formSubmitted: boolean = false;
constructor(
private _formBuilder: FormBuilder,
private _store: Store<IAppState>,
) {
this.pageState$ = this._store.select(selectLoginPageState) as Observable<
ILoginPageState
>;
this._buildForm();
}
ngOnInit() {
this._animatePage();
}
public onFormSubmit() {
this.formSubmitted = true;
if (this.form.invalid) {
return;
}
this._store.dispatch(Login(this.form.value));
}
private _buildForm() {
this.form = this._formBuilder.group({
email: this._formBuilder.control(
null,
[Validators.required, Validators.email],
[this.test.bind(this)],
),
password: this._formBuilder.control(null, Validators.required),
});
}
private test(control: AbstractControl) {
return this._store.select(selectLoginErrorMessage).pipe(
tap(() => console.log('executing')),
map(value => ({
foo: true
})),
);
}
private _animatePage() {
this.transitionController.animate(
new Transition(EAnimationType.FadeUp, 500, TransitionDirection.In),
);
}
}
login-page.effects.ts
@Injectable()
export class LoginEffects {
constructor(
private _actions$: Actions,
private _authService: AuthenticationSevice,
private _router: Router,
private _modalService: SuiModalService,
private _store: Store<IAppState>,
) {}
Login$ = createEffect(() => {
return this._actions$.pipe(
ofType(AuthActions.Login),
tap(() => this._store.dispatch(ShowPageLoader())),
switchMap((credentials: ILoginCredentials) =>
this._authService.login(credentials).pipe(
map((response: ILoginResponse) => AuthActions.LoginSuccess(response)),
catchError((response: HttpErrorResponse) => {
let validationErrors: ValidationErrors;
switch (response.status) {
case HttpStatusCode.BAD_REQUEST:
validationErrors = {
error: {
validationErrors: response.error,
generalError:
'Oops! We found some errors with your provided details.',
},
};
break;
case HttpStatusCode.NOT_FOUND:
validationErrors = {
error: {generalError: 'Email or password is incorrect.'},
};
break;
}
return of(AuthActions.LoginFailure(validationErrors));
}),
finalize(() => this._store.dispatch(HidePageLoader())),
),
),
);
});
LoginSuccess$ = createEffect(
() => {
return this._actions$.pipe(
ofType(AuthActions.LoginSuccess),
tap(() => {
this._modalService.open(
new ModalComponent<IModalContext>(undefined, {
title: 'Login successful',
imageSrc: 'assets/images/modal/login-successful.png',
}),
);
this._router.navigateByUrl('/home');
}),
);
},
{dispatch: false},
);
}
ここでの主な問題は、私のtest
メソッド内にあります。エラーフィールドに を設定したいのです{ foo : true}
が、決して起こりません。私はグーグルでたくさん検索しましたが、私が見つけた1つの解決策は、オブザーバブルが完了first()
するようにメソッドを内部に追加することでした。pipe()
それは機能しましたが、最初だけでした。さらに、フォームが送信されたときに非同期バリデーターが呼び出されることはありませんでした。
インターネットで見つけたすべての例は、Http 呼び出しを使用していました。リクエストが完了するとオブザーバブルが完了することを理解していますが、私の場合、そのHttp呼び出しは私の内部で処理されていますlogin-page.effects.ts
それを行うより良い方法はありますか?または、よく知らない RxJs オペレーターが必要ですか?