如何通过原型扩展FormControl功能?实现markAsDirty触发onMarkAsDirty
实现带
onMarkAsDirty事件的FormControl 方案1:自定义继承FormControl的类
这种方式更可控,避免全局原型修改带来的潜在副作用:
import { FormControl, ValidatorFn, AsyncValidatorFn } from '@angular/forms'; import { Subject } from 'rxjs'; export class CustomFormControl extends FormControl { // 用于发射markAsDirty触发事件的可观察对象 readonly onMarkAsDirty = new Subject<void>(); constructor( formState?: any, validatorOrOpts?: ValidatorFn | ValidatorFn[] | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null ) { super(formState, validatorOrOpts, asyncValidator); } // 重写markAsDirty方法,触发事件 markAsDirty(opts?: { onlySelf?: boolean }): void { super.markAsDirty(opts); this.onMarkAsDirty.next(); } }
使用示例
// 创建自定义控件实例 const control = new CustomFormControl('初始值'); // 订阅脏值标记事件 control.onMarkAsDirty.subscribe(() => { console.log('控件已被标记为脏值!'); }); // 调用markAsDirty会触发订阅回调 control.markAsDirty();
结合FormBuilder使用:
import { FormBuilder } from '@angular/forms'; // 组件内代码 constructor(private fb: FormBuilder) { const form = this.fb.group({ username: new CustomFormControl('') }); const usernameControl = form.get('username') as CustomFormControl; usernameControl.onMarkAsDirty.subscribe(() => { console.log('用户名控件变为脏值'); }); }
方案2:扩展FormControl全局原型
如果需要所有FormControl实例都具备该功能,可以通过扩展原型实现,建议在应用启动时(如app.module.ts的ngOnInit)执行以下代码:
import { FormControl } from '@angular/forms'; import { Subject } from 'rxjs'; // 保存原生markAsDirty方法 const originalMarkAsDirty = FormControl.prototype.markAsDirty; // 为原型添加懒加载的onMarkAsDirty属性 Object.defineProperty(FormControl.prototype, 'onMarkAsDirty', { get() { if (!this._onMarkAsDirty) { this._onMarkAsDirty = new Subject<void>(); } return this._onMarkAsDirty; }, enumerable: true, configurable: true }); // 重写markAsDirty方法,触发事件 FormControl.prototype.markAsDirty = function(opts?: { onlySelf?: boolean }) { originalMarkAsDirty.call(this, opts); this._onMarkAsDirty?.next(); };
使用示例
所有FormControl实例(包括FormBuilder创建的)都会自动拥有onMarkAsDirty属性:
import { FormBuilder } from '@angular/forms'; constructor(private fb: FormBuilder) { const form = this.fb.group({ email: [''] }); const emailControl = form.get('email') as FormControl; emailControl.onMarkAsDirty.subscribe(() => { console.log('邮箱控件被标记为脏值'); }); emailControl.markAsDirty(); // 触发订阅回调 }
TypeScript类型补充
为避免类型报错,可在项目的typings.d.ts中添加类型扩展:
import { Subject } from 'rxjs'; declare module '@angular/forms' { interface FormControl { _onMarkAsDirty?: Subject<void>; onMarkAsDirty: Subject<void>; } }
内容的提问来源于stack exchange,提问作者Anton Minchenko
相关产品推荐
相关产品推荐

