提问人:Elliott Alderson 提问时间:10/4/2023 最后编辑:Elliott Alderson 更新时间:10/6/2023 访问量:34
提交有效表单和更改样式
Submitting valid form and changing style
问:
我有一个 Angular 15 应用程序。我正在使用 Angular 材质进行造型设计。 我只想提交有效的表格,即没有一个字段应该是空的,电子邮件字段必须是电子邮件。
这是我的表单的样子:
` <form #form="ngForm" (ngSubmit)="onFormSubmit()" class="py-3">
<div class="row">
<mat-form-field class="col">
<mat-label>First name</mat-label>
<input matInput placeholder="Ex: Jhon" [formControl]="fnameFormControl" [errorStateMatcher]="matcher" [(ngModel)]="model.fname" name="fname">
<mat-error *ngIf="fnameFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="col">
<mat-label>Last name</mat-label>
<input matInput placeholder="Ex: Doe" [formControl]="lnameFormControl" [errorStateMatcher]="matcher" [(ngModel)]="model.lname" name="lname">
<mat-error *ngIf="lnameFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row pb-3">
<div class="col">
<input type="tel" id="phone" class="w-100 form-control" [(ngModel)]="model.phone" name="phone">
<span id="error-msg" class="d-none error-msg"></span>
</div>
</div>
<mat-form-field class="form-group w-100">
<mat-label>Email</mat-label>
<input type="email" matInput [formControl]="emailFormControl" [errorStateMatcher]="matcher" [(ngModel)]="model.email" name="email"
placeholder="Ex. [email protected]">
<!-- <mat-hint>Errors appear instantly!</mat-hint> -->
<mat-error *ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf="emailFormControl.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="w-100">
<mat-label>Choose a breed</mat-label>
<mat-select [formControl]="breedSelectFormControl" [errorStateMatcher]="matcher" [(ngModel)]="model.breed" name="breed">
<mat-option *ngFor="let breedof breeds" [value]="breed.value">
{{breed.viewValue}}
</mat-option>
</mat-select>
<mat-error *ngIf="breedSelectFormControl.hasError('required')">
Please select on option
</mat-error>
</mat-form-field>
<mat-form-field class="w-100">
<mat-label>Share your story with us</mat-label>
<textarea matInput placeholder="Write it here..." [formControl]="storyFormControl" [errorStateMatcher]="matcher" [(ngModel)]="model.story" name="story"></textarea>
<mat-error *ngIf="storyFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
<div class="form-group pt-3">
<button class="btn btn-warning btn-block w-100 " id="contact-btn">Get a free consultation</button>
</div>
</form>`
同一组件的.ts逻辑如下所示:
import { Component } from '@angular/core';
import {
FormControl,
FormGroupDirective,
NgForm,
Validators,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import {MatSelectModule} from '@angular/material/select';
import {ErrorStateMatcher} from '@angular/material/core';
import {NgIf, NgFor} from '@angular/common';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import { addBreed Request } from '../model/add-breed-request.model';
/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
interface Breed {
value: string;
viewValue: string;
}
@Component({
selector: 'app-contact-card',
templateUrl: './contact-card.component.html',
styleUrls: ['./contact-card.component.css'],
standalone: true,
imports: [FormsModule, MatSelectModule , MatFormFieldModule, MatInputModule, ReactiveFormsModule, NgIf , NgFor],
})
export class ContactCardComponent {
//base model
model: addBreedRequest;
emailFormControl = new FormControl('', [Validators.required, Validators.email]);
fnameFormControl = new FormControl('',[Validators.required]);
lnameFormControl = new FormControl('',[Validators.required]);
breedSelectFormControl = new FormControl('',[Validators.required]);
storyFormControl = new FormControl('',[Validators.required]);
matcher = new MyErrorStateMatcher();
breeds: Breed[] = [
{value: '1', viewValue: 'German Shepherd'},
{value: '2', viewValue: 'German Longhaired Pointer'},
{value: '3', viewValue: 'German Pinscher'},
{value: '4', viewValue: 'German Shepherd Dog'},
{value: '5', viewValue: 'German Shorthaired Pointer'},
{value: '6', viewValue: 'German Wirehaired Pointer'},
{value: '7', viewValue: 'German Spitz'}
];
constructor(){
this.model = {
fname: '',
lname: '',
email: '',
phone: '',
breed: '',
story: ''
}
}
onFormSubmit(){
// here I want to check if form is valid.
console.log(this.model);
// expectations:
if(form.isValid()){
// submit request and change form style.
}
}
}
视觉验证工作得很好,但是当我尝试将表单传递给 onFormSubmit() 时,即使有空字段,它也显示表单有效。
我尝试了这样的事情:
<form #form="ngForm" (ngSubmit)="onFormSubmit(**form**)" class="py-3">
// and in .ts file
onFormSubmit(form:FormControl){
console.log(form.isValid()); // outputing valid all the time.
}
更新:此外,我在浏览器控制台中收到此消息:
看起来您正在与 formControl 在同一表单字段上使用 ngModel。 支持将 ngModel 输入属性和 ngModelChange 事件与 反应式表单指令已在 Angular v6 中弃用,将被删除 在 Angular 的未来版本中。
有关更多信息,请参阅此处的 API 文档:https://angular.io/api/forms/FormControlDirective#use-with-ngmodel
答:
你不应该将 Angular Form (NgForm) 与 Reactive Form 混合在一起。
当您将验证规则(例如)设置为 时,验证将仅在 中进行。虽然实例不应用验证,但返回并与 s 的结果冲突。Validators.required
FormControl
FormControl
NgForm
form.valid
true
FormControl
提供了将当前代码迁移到反应式表单的答案。
从 HTML 中删除。
[(ngModel)]
创建包含多个 s 的实例。
FormGroup
FormControl
在元素中添加属性。
[formGroup]="form"
<form>
替换为 。
[formControl]
formControlName
将所有变量修改为一个 getter 函数,该函数从实例中检索相应的变量。
FormControl
FormControl
form
FormGroup
您可以将该值修补为 via .
model
FormGroup
patchValue()
您的最终代码应如下所示:
<form [formGroup]="form" (ngSubmit)="onFormSubmit()" class="py-3">
<div class="row">
<mat-form-field class="col">
<mat-label>First name</mat-label>
<input
matInput
placeholder="Ex: Jhon"
formControlName="fname"
[errorStateMatcher]="matcher"
name="fname"
/>
<mat-error *ngIf="fnameFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="col">
<mat-label>Last name</mat-label>
<input
matInput
placeholder="Ex: Doe"
formControlName="lname"
[errorStateMatcher]="matcher"
name="lname"
/>
<mat-error *ngIf="lnameFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row pb-3">
<mat-form-field class="col">
<mat-label>Phone</mat-label>
<input
matInput
type="tel"
class="w-100 form-control"
formControlName="phone"
[errorStateMatcher]="matcher"
name="phone"
/>
<mat-error *ngIf="phoneFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<mat-form-field class="form-group w-100">
<mat-label>Email</mat-label>
<input
type="email"
matInput
formControlName="email"
[errorStateMatcher]="matcher"
name="email"
placeholder="Ex. [email protected]"
/>
<!-- <mat-hint>Errors appear instantly!</mat-hint> -->
<mat-error
*ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')"
>
Please enter a valid email address
</mat-error>
<mat-error *ngIf="emailFormControl.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="w-100">
<mat-label>Choose a breed</mat-label>
<mat-select
formControlName="breed"
[errorStateMatcher]="matcher"
name="breed"
>
<mat-option *ngFor="let breed of breeds" [value]="breed.value">
{{breed.viewValue}}
</mat-option>
</mat-select>
<mat-error *ngIf="breedSelectFormControl.hasError('required')">
Please select on option
</mat-error>
</mat-form-field>
<mat-form-field class="w-100">
<mat-label>Share your story with us</mat-label>
<textarea
matInput
placeholder="Write it here..."
formControlName="story"
[errorStateMatcher]="matcher"
name="story"
></textarea>
<mat-error *ngIf="storyFormControl.hasError('required')">
Field is <strong>required</strong>
</mat-error>
</mat-form-field>
<div class="form-group pt-3">
<button class="btn btn-warning btn-block w-100" id="contact-btn">
Get a free consultation
</button>
</div>
</form>
form = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
fname: new FormControl('', [Validators.required]),
lname: new FormControl('', [Validators.required]),
phone: new FormControl('', [Validators.required]),
breed: new FormControl('', [Validators.required]),
story: new FormControl('', [Validators.required]),
});
get emailFormControl() {
return this.form.controls['email'] as FormControl;
}
get fnameFormControl() {
return this.form.controls['fname'] as FormControl;
}
get lnameFormControl() {
return this.form.controls['lname'] as FormControl;
}
get phoneFormControl() {
return this.form.controls['phone'] as FormControl;
}
get breedSelectFormControl() {
return this.form.controls['breed'] as FormControl;
}
get storyFormControl() {
return this.form.controls['story'] as FormControl;
}
ngOnInit() {
this.form.patchValue(this.model);
}
onFormSubmit() {
console.log(this.form.valid);
}
评论