#angular #angular-reactive-forms
#угловые #угловые реактивные формы
Вопрос:
У меня есть следующая простая форма. Я хочу кнопку, которая проверяет, доступно ли имя пользователя в одном конкретном поле. Если имя пользователя доступно, то основная кнопка отправки включена. Как мне этого добиться? Это форма внутри формы?
<form mat-dialog-content [formGroup]="myForm">
<mat-form-field>
<input matInput formControlName="firstName" />
<mat-error>{{ error }}</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput formControlName="lastName" />
<mat-error>{{ error }}</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput formControlName="username" />
<mat-error>{{ error }}</mat-error>
</mat-form-field>
//This button needs to be disabled unless username is filled out. If user changes username the main submit button should be disabled unless user checks with this button.
<button (click)="userNameCheck()" >Check if available</button>
<mat-form-field>
<input matInput formControlName="notes" />
<mat-error>{{ error }}</mat-error>
</mat-form-field>
<button (click)="save()" [disabled]="myForm.invalid">Submit</button>
</form>
export const FORM_CONTROLS = {
firstName: [null, Validators.required],
lastName: [null, Validators.required],
username: [null, Validators.required],
notes: [null],
}
this.myForm = this.formBuilder.group(FORM_CONTROLS);
save() {
const myData = this.myForm.value;
this.myService.saveData(myData);
}
Ответ №1:
Иметь форму внутри формы — плохая практика. «форма не должна содержать других элементов формы. Запреты HTML
Лучшим подходом было бы объявить свойство, например, usernameCheckField
и включить его в привязку формы к ngModel
см. Пример ниже
<input type="password" [(ngModel)] = "usernameCheckField" [ngModelOptions]="{standalone: true}" />
обратите внимание на [ngModelOptions]="{standalone: true}"
. Это позволит вам использовать шаблон, управляемый для модели, внутри модели реактивных форм.
Лучшим подходом к проверке, существует ли пользователь, было бы подписаться на valueChanges
свойство username
поля в вашем ngOnInit
крючке жизненного цикла
ngOnInit() {
this.myForm.get("username").valueChanges.pipe(
mergeMap((username) => this.myService.checkIfUserExists(username)),
tap(res => {
// Do some operations here
})
).subscribe()
}
Не забудьте отказаться от подписки!. Вы можете рассмотреть возможность использования takeWhile
операторов takeUntil
из rxjs/operators
для этого
Комментарии:
1. Является ли это рекомендуемым подходом? Похоже, что это уходит от формы, используя реактивные формы?
2. @Owen, помните, что изменения значений происходят при изменении входных данных, это предполагает несколько вызовов службы
3. @KingKongFrog, «рекомендуемый подход» заключается в использовании асинхронных валидаторов: angular.io/guide /… . Другой подход заключается в том, что кнопка всегда была включена, и перед отправкой проверьте, существует ли сообщение электронной почты.
4. @KingKongFrog @Eliseo Я предоставил второй подход, чтобы гарантировать, что вы поддерживаете реактивный подход к форме. Для проблемы с несколькими вызовами рассмотрите возможность передачи
debounce
оператора и установки интервала между вводом пользователем и временем вызова службы, и вместоmergeMap
использованияswitchMap
, которое отменяет ранее наблюдаемое, когда предоставляется новый поток, в данном случае, когда пользователь вводит