Angular数字输入自定义指令如何获取父级响应式FormGroup与FormControl
解决方案
问题根源
直接调用原生stepUp()/stepDown()方法修改输入框值的操作,只会更新DOM的value属性,不会触发浏览器默认的input/change事件,Angular响应式表单依赖监听这些事件完成值同步、状态更新,所以才会出现值不联动、状态不变更的问题。
实现方案
通过注入NgControl获取当前输入框绑定的FormControl实例,修改值后主动同步到表单、更新控件状态即可。NgControl是Angular所有表单控件的基类,不管是响应式表单的formControlName还是模板驱动的ngModel绑定,都可以直接注入拿到对应控件实例,无需手动关联父级FormGroup。
修改后的完整指令代码
import { Directive, ElementRef, Renderer2, OnInit } from '@angular/core'; import { NgControl } from '@angular/forms'; @Directive({ selector: '[numberControls]' }) export class NumberControlsDirective implements OnInit { constructor( private elementRef: ElementRef, private renderer: Renderer2, // 注入当前输入框关联的表单控件实例 private ngControl: NgControl ) { } ngOnInit(): void { this.createStuctureAndControls(); } createStuctureAndControls(): void { const parent = this.elementRef.nativeElement.parentNode; const containerElement = this.renderer.createElement('div'); const firstRowElement = this.renderer.createElement('div'); this.renderer.appendChild(firstRowElement, this.elementRef.nativeElement); this.renderer.appendChild(containerElement, firstRowElement); const controlsElement = this.renderer.createElement('div'); const firstControl = this.renderer.createElement('div'); const secondControl = this.renderer.createElement('div'); firstControl.innerHTML = '-'; secondControl.innerHTML = '+'; firstControl.addEventListener('click', this.onClickDecrease.bind(this)); secondControl.addEventListener('click', this.onClickIncrease.bind(this)); this.renderer.appendChild(controlsElement, firstControl); this.renderer.appendChild(controlsElement, secondControl); this.renderer.appendChild(firstRowElement, controlsElement); this.renderer.appendChild(parent, containerElement); this.renderer.removeAttribute(this.elementRef.nativeElement, 'numberControls'); } onClickDecrease(): void { this.elementRef.nativeElement.stepDown(); this.syncValueToForm(); } onClickIncrease(): void { this.elementRef.nativeElement.stepUp(); this.syncValueToForm(); } // 新增同步值和状态的方法 private syncValueToForm(): void { const inputEl = this.elementRef.nativeElement; // 两种实现二选一即可 // 方案1:手动更新FormControl的值和状态,自定义程度更高 this.ngControl.control.setValue(inputEl.value); this.ngControl.control.markAsDirty(); this.ngControl.control.markAsTouched(); // 方案2:手动派发input事件,触发Angular默认的表单值同步逻辑,代码更简洁 // inputEl.dispatchEvent(new Event('input')); } }
使用说明
原有HTML调用代码不需要做任何修改,和你之前的用法保持一致即可正常工作,同时兼容响应式表单和模板驱动表单场景。
内容的提问来源于stack exchange,提问作者NewToAngular
相关产品推荐
相关产品推荐

