面试题答案
一键面试1. 设计表单结构
- 使用
FormGroup
和FormArray
:- 顶级
FormGroup
代表整个订单表单。 - 对于订单中的商品(表单数组),使用
FormArray
。 - 每个商品的属性(表单组)使用
FormGroup
。
- 顶级
- 双向数据绑定:
- 在模板中,使用
[(ngModel)]
进行双向数据绑定,并结合name
属性。例如:
<input type="text" [(ngModel)]="data.property" name="property">
- 对于
FormArray
中的元素,在*ngFor
循环中绑定数据。例如:
<div formArrayName="products"> <div *ngFor="let product of orderForm.get('products').controls; let i = index" [formGroupName]="i"> <input type="text" [(ngModel)]="product.name" name="name"> </div> </div>
- 在模板中,使用
- 验证:
- 对于单个表单控件,可以使用 Angular 内置的验证器,如
required
、minlength
等。例如:
<input type="text" [(ngModel)]="data.property" name="property" required>
- 对于
FormGroup
和FormArray
,可以自定义验证器。例如,自定义一个验证商品数量不能为负数的验证器:
export function quantityValidator(control: AbstractControl): { [key: string]: any } | null { const quantity = control.get('quantity'); if (quantity && quantity.value < 0) { return { negativeQuantity: true }; } return null; }
- 在创建
FormGroup
时应用自定义验证器:
const productFormGroup = new FormGroup({ name: new FormControl('', Validators.required), quantity: new FormControl(0, [Validators.required, Validators.min(0)]), }, { validators: quantityValidator });
- 对于单个表单控件,可以使用 Angular 内置的验证器,如
2. 提交表单时的验证及错误处理
- 验证表单有效性:
- 在提交按钮的点击事件中,检查顶级
FormGroup
的有效性。例如:
<button (click)="onSubmit()" [disabled]="!orderForm.valid">提交</button>
onSubmit() { if (this.orderForm.valid) { // 处理表单提交逻辑 } else { // 处理验证错误 this.validateAllFormFields(this.orderForm); } }
- 在提交按钮的点击事件中,检查顶级
- 处理验证错误:
- 遍历表单控件,标记所有无效控件,以便在模板中显示错误信息。
validateAllFormFields(formGroup: FormGroup) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); } else if (control instanceof FormGroup) { this.validateAllFormFields(control); } else if (control instanceof FormArray) { control.controls.forEach(c => { if (c instanceof FormGroup) { this.validateAllFormFields(c); } }); } }); }
- 在模板中显示错误信息,例如:
<input type="text" [(ngModel)]="product.name" name="name" required> <div *ngIf="orderForm.get('products').get(i).get('name').hasError('required') && (orderForm.get('products').get(i).get('name').touched || orderForm.get('products').get(i).get('name').dirty)"> 商品名称是必填项 </div>
3. 核心代码示例
- 组件类代码(TypeScript):
import { Component } from '@angular/core'; import { FormGroup, FormControl, FormArray, Validators, AbstractControl } from '@angular/forms'; export function quantityValidator(control: AbstractControl): { [key: string]: any } | null { const quantity = control.get('quantity'); if (quantity && quantity.value < 0) { return { negativeQuantity: true }; } return null; } @Component({ selector: 'app-order-form', templateUrl: './order - form.component.html', styleUrls: ['./order - form.component.css'] }) export class OrderFormComponent { orderForm: FormGroup; constructor() { this.orderForm = new FormGroup({ products: new FormArray([]) }); this.addProduct(); } addProduct() { const productFormGroup = new FormGroup({ name: new FormControl('', Validators.required), quantity: new FormControl(0, [Validators.required, Validators.min(0)]), }, { validators: quantityValidator }); (this.orderForm.get('products') as FormArray).push(productFormGroup); } onSubmit() { if (this.orderForm.valid) { console.log('表单提交成功', this.orderForm.value); } else { this.validateAllFormFields(this.orderForm); } } validateAllFormFields(formGroup: FormGroup) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); } else if (control instanceof FormGroup) { this.validateAllFormFields(control); } else if (control instanceof FormArray) { control.controls.forEach(c => { if (c instanceof FormGroup) { this.validateAllFormFields(c); } }); } }); } }
- 模板代码(HTML):
<form [formGroup]="orderForm"> <div formArrayName="products"> <div *ngFor="let product of orderForm.get('products').controls; let i = index" [formGroupName]="i"> <h3>商品 {{i + 1}}</h3> <input type="text" formControlName="name" placeholder="商品名称" required> <div *ngIf="orderForm.get('products').get(i).get('name').hasError('required') && (orderForm.get('products').get(i).get('name').touched || orderForm.get('products').get(i).get('name').dirty)"> 商品名称是必填项 </div> <input type="number" formControlName="quantity" placeholder="商品数量" required> <div *ngIf="orderForm.get('products').get(i).get('quantity').hasError('required') && (orderForm.get('products').get(i).get('quantity').touched || orderForm.get('products').get(i).get('quantity').dirty)"> 商品数量是必填项 </div> <div *ngIf="orderForm.get('products').get(i).hasError('negativeQuantity') && (orderForm.get('products').get(i).touched || orderForm.get('products').get(i).dirty)"> 商品数量不能为负数 </div> </div> </div> <button type="button" (click)="addProduct()">添加商品</button> <button type="submit" (click)="onSubmit()" [disabled]="!orderForm.valid">提交</button> </form>