Angular2 - проверка и отправка формы извне
У меня есть простая форма, которая выглядит так
<form (ngSubmit)="save()" #documentEditForm="ngForm">
...
</form>
и необходимо отправить форму и проверить ее действительность извне
например. Либо отправьте его программно, либо с <button type="submit">
который находится за пределами тегов <form>
.
Ответы
Ответ 1
Узнал, как это сделать:
- инициировать отправку с помощью
<formname>.ngSubmit.emit()
- получить статус формы с помощью
<formname>.form.valid
Пример:
<form (ngSubmit)="save()" #documentEditForm="ngForm">
...
</form>
<button class="btn-save button primary"
(click)="documentEditForm.ngSubmit.emit()"
[disabled]="!documentEditForm.form.valid">SAVE</button>
Редактировать: Как @yuriy-yakovenko указал, вы должны добавить в свой код компонента следующее:
@ViewChild('documentEditForm') documentEditForm: FormGroupDirective;
И не забудьте импортировать FormGroupDirective
если вы еще этого не сделали
Ответ 2
Правильный способ делать на самом деле
<form (ngSubmit)="save()" id="ngForm" #documentEditForm="ngForm">
...
</form>
<button class="btn-save button primary" form="ngForm" [disabled]="!documentEditForm.form.valid">
SAVE
</button>
Форма должна иметь идентификатор id="example-form"
, а кнопка отправки - соответствующий идентификатор в form="example-form"
Ответ 3
Важно: при использовании угловых элементов управления формы материала + реактивных форм
Вызовите onSubmit(undefined)
чтобы правильно установить [formGroup]
submitted = true
в директиве [formGroup]
Примечание: директива не является тем же объектом, что и сама угловая форма (подробнее об этом ниже)
Здесь часть исходного кода для директивы [formGroup]
. (для реактивных форм)
@Directive({
selector: '[formGroup]',
providers: [formDirectiveProvider],
host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
exportAs: 'ngForm'
})
export class FormGroupDirective extends ControlContainer implements Form,
OnChanges {
/**
* @description
* Reports whether the form submission has been triggered.
*/
public readonly submitted: boolean = false;
.....
onSubmit($event: Event): boolean {
(this as{submitted: boolean}).submitted = true;
syncPendingControls(this.form, this.directives);
this.ngSubmit.emit($event);
return false;
}
Вы используете это так:
<form [formGroup]="form" #formRef="ngForm">
И вы можете получить ссылку на FormGroupDirective
в вашем ts
файл с:
@ViewChild('formRef')
formRef: FormGroupDirective;
- Примечание.
NgForm
- это еще одна директива, автоматически применяемая при создании <form>
. - Смущающее примечание: как
NgForm
и FormGroupDirective
имеют в своем исходном коде exportAs: 'ngForm'
(и они также объявляют submitted
свойства и свойства ngSubmit
). Но когда я ставлю #ngForm='ngForm'
я получаю объект типа FormGroupDirective
а не NgForm
(проверено в отладчике). Я не уверен точно, почему - но именно поэтому я объявил это как FormGroupDirective
а не NgForm
- я думаю, может быть, первые NgForm
.
Вы используете это так:
this.formRef.onSubmit(undefined)
Пример:
// html
<form [formGroup]="form" #formRef="ngForm">
// ...Form Controls
</form>
// component.ts
export class MyComponent {
@ViewChild('formRef')
formRef: FormGroupDirective;
form: FormGroup = new FormGroup({
myInput: new FormControl(''),
//etc...
});
submitFormProgrammatically() {
this.formRef.onSubmit(undefined);
}
}
Если бы вы просто this.formRef.ngSubmit.emit()
как предлагали некоторые другие ответы, вы не получите все важные значения submitted = true
.
Почему это важно?
Если вы используете какие-либо элементы управления Angular CDK или Angular Material, условие ошибки не отображается, если к полю формы не было прикосновения (нажатие или получение фокуса) ИЛИ форма была отправлена целиком.
Поэтому, если у вас отсутствует обязательное поле, которое мышь/курсор никогда не ngSubmit.emit()
тогда это поле не будет отображаться красным, даже если вы выполните ngSubmit.emit()
(потому что для формы submitted = false
а элемент управления touched = false
).
Так как же это нормально работает с обычной кнопкой отправки?
Обычно, если у вас есть <button type='submit'>Submit</button>
(внутри <form>
), это вызовет отправку стандартного HTML <form>
(ничего общего с Angular) - и это приведет к стандартному submit
событие в теге формы.
ЕСЛИ этот <form>
также имеет директиву [formGroup]
(как показано выше), то событие submit
формы HTML 'перехватывается' директивой и вызывает то, что вызывает onSubmit()
выше.
Это, в свою очередь, вызывает событие ngSubmit
- которое вы можете поймать сами, если вам потребуется дополнительная обработка - например, показ предупреждения.
Поэтому очень важно вызвать onSubmit
а не ngSubmit.emit
чтобы заставить работать валидацию при использовании элементов управления материалом. Параметр $ event может быть нулевым или неопределенным.
Дальнейшее чтение: Посмотрите на ErrorStateMatcher
(только для Angular CDK/Material), чтобы увидеть точные правила. Вы можете создать свой собственный, если обойти ограничения по умолчанию становится слишком сложным.
Еще более запутанно: директива [formGroup]
НЕ является тем же объектом, что и FormGroup
которая просто хранит данные. Только директива submitted
его - тогда как у FormGroup
есть такие вещи, как touched
, pristine
, dirty
.
Ответ 4
Если вы используете Reactive Forms, используйте свойство formGroup invalid для отключения кнопки отправки:
<button
form="ngForm"
[disabled]=" editor.invalid>Enviar</button>
...
<form [formGroup]="editor" id="ngForm" (ngSubmit)="save()" novalidate >
...
</form>
Ответ 5
Трюк, который работал у меня с помощью
- Реактивные формы
- Angular2
- вкл. IE
:
<!-- real button will simulate click on invisible button (cf. form) -->
<button onclick="document.getElementById('hiddenSaveButtonForMicrosoftWithLove').click()">
The Real Button outside forms
</button>
<form>
<!-- will be called in the background and is never visible -->
<button id="hiddenSaveButtonForMicrosoftWithLove" type="submit" style="display: none;">hiddenSaveButtonForMicrosoftWithLove</button>
</form>
Ответ 6
Ниже решение работает в моем случае, пожалуйста, попробуйте это простое решение. Я не уверен, будет ли это работать во всех условиях:
<form #documentEditForm="ngForm" id="ngForm" (ngSubmit)="save(documentEditForm.valid)">
...Your Input Elements...
</form>
Кнопка должна быть объявлена вне формы следующим образом:
<button form="ngForm">Submit</button>
Валидация формы должна проверяться в save() при соблюдении следующих условий
save(isValid:boolean){
if(isValid) {
...Your code to save details...
}
}
Надеюсь, это простое решение поможет вам.
Ответ 7
Этот пример будет работать в Angular 6 и выше
<form (ngSubmit)="save()" id="ngForm" [formGroup]="form">
...
</form>
<button type="submit" class="btn-save button primary" form="ngForm">Save</button>