如何基于验证规则修改Angular自定义表单控件组件?
实现自定义表单控件的必填星号显示方案
核心思路
要同时兼容模板驱动表单(直接传入required属性)和响应式表单(配置Validators.required),需要结合输入属性和表单控件的验证状态来判断是否显示必填星号。通过注入NgControl可以获取当前表单控件的验证信息,再配合自定义的required输入属性,就能覆盖两种场景。
具体实现步骤
1. 修改组件代码,注入NgControl并添加相关逻辑
在组件中注入NgControl,同时添加required输入属性,再创建计算属性判断是否需要显示星号:
import { Component, Input, OnChanges, SimpleChanges, forwardRef, Self, Optional } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR, NgControl, Validators } from '@angular/forms'; @Component({ selector: 'app-input', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './input.component.html', styleUrls: ['./input.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputComponent), multi: true } ] }) export class InputComponent implements ControlValueAccessor, OnChanges { protected _value: any = ''; protected _touched: boolean = false; protected _disabled: boolean = false; protected _onChange: any = () => {}; protected _onTouch: any = () => {}; @Input() type: string = 'text'; @Input() label: string = ''; @Input() required: boolean = false; // 支持模板驱动传入required constructor( @Self() @Optional() public ngControl: NgControl // 注入NgControl获取验证状态 ) { if (this.ngControl) { this.ngControl.valueAccessor = this; } } // 计算属性:判断是否需要显示必填星号 get isRequired(): boolean { // 两种情况:1. 输入的required为true;2. 控件配置了required验证器 const hasRequiredValidator = this.ngControl?.control?.hasValidator(Validators.required) || false; return this.required || hasRequiredValidator; } writeValue(value: any): void { this._value = value; } registerOnChange(fn: any): void { this._onChange = fn; } registerOnTouched(fn: any): void { this._onTouch = fn; } setDisabledState?(isDisabled: boolean): void { this._disabled = isDisabled; } onChange(value: any): void { if (!this._disabled) { this._onChange(value); } } onBlur(): void { if (!this._touched) { this._onTouch(); this._touched = true; } } }
2. 修改组件模板,添加星号显示逻辑
在模板的标签部分,根据isRequired计算属性来显示星号:
<div class="input-container"> <label *ngIf="label"> {{ label }} <span *ngIf="isRequired" class="required-asterisk">*</span> </label> <input [type]="type" [value]="_value" [disabled]="_disabled" (input)="onChange($event.target.value)" (blur)="onBlur()" > </div>
3. 样式优化(可选)
给星号添加样式,让它更醒目:
.required-asterisk { color: #dc3545; margin-left: 4px; }
两种场景的使用示例
模板驱动表单场景
直接给组件传入required属性:
<app-input label="用户名" required></app-input>
响应式表单场景
在表单组中配置Validators.required:
// 父组件类中定义表单 import { FormBuilder, FormGroup, Validators } from '@angular/forms'; export class ParentComponent { myForm: FormGroup; constructor(private fb: FormBuilder) { this.myForm = this.fb.group({ email: ['', Validators.required] }); } }
模板中使用:
<form [formGroup]="myForm"> <app-input label="邮箱" formControlName="email"></app-input> </form>
关键说明
- 注入
NgControl时必须加@Self()和@Optional(),避免与父组件的表单控件产生依赖冲突。 isRequired计算属性同时覆盖了模板驱动的输入属性和响应式表单的验证器配置,确保两种场景都能正确显示星号。- 如果需要更精确的判断(比如只在控件触及时显示星号),可以调整
isRequired的逻辑,结合_touched或ngControl.control.touched来判断。
内容的提问来源于stack exchange,提问作者Matheus Alencar
相关产品推荐
相关产品推荐

