我正在开发一个 Angular 8 应用程序。我想使用 NgRx 存储和使用自定义异步验证器的反应式表单来显示表单错误。
登录组件.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),
);
}
}
登录页面.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}
错误字段上设置,但它永远不会发生。我在谷歌上搜索了很多,我发现的一个解决方案是在first()
里面添加方法,pipe()
以便我的 observable 完成。它起作用了,但只是第一次。另外,提交表单时从未调用过异步验证器。
我在互联网上找到的所有示例都是使用 Http 调用。我知道它在请求完成时完成了 observable 但在我的情况下,Http 调用正在我的内部处理login-page.effects.ts
有没有更好的方法呢?还是我需要一些我不熟悉的 RxJs 运算符?