Я разрабатываю приложение Angular 8. Я хочу отображать ошибки формы, используя хранилище NgRx и реактивные формы, используя собственный асинхронный валидатор.
логин.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),
);
}
}
страница входа.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}
было установлено в поле ошибки, но этого никогда не происходит. Я искал тонну в Google, и одно решение, которое я нашел, заключалось в том, чтобы добавить метод first()
внутри pipe()
, чтобы мой наблюдаемый объект был завершен. Это сработало, но только в самый первый раз. Кроме того, асинхронный валидатор никогда не вызывался при отправке формы.
Все примеры, которые я нашел в Интернете, использовали вызов Http. Я понимаю, что он завершает наблюдаемое, когда запрос завершен, но в моем случае этот вызов Http обрабатывается внутри моего login-page.effects.ts
Есть ли лучший способ сделать это? или мне нужен какой-то оператор RxJs, с которым я не знаком?