英文:
Angular Custom Control: change event isn't triggered in reactive form
问题
这段代码曾经运行良好,直到我发现它出了问题。我面临的问题如下:
我有一个抽象值访问器类,被多个自定义表单控件继承。它的结构如下:
@Directive()
export abstract class AbstractInputComponent implements OnChanges {
@Input() public isReadOnly = false;
protected innerValue: unknown = null;
public registerOnChange(fn: any) { this.propagateChange = fn; }
public registerOnTouched(fn: any) { this.propagateTouch = fn; }
public propagateChange = (_: any) => { };
public propagateTouch = (_: any) => { };
public ngOnChanges(): void {
if ( this.isReadOnly ) {
this.propagateChange(this.value);
}
this.cdr.detectChanges();
}
public get value(): any {
return this.innerValue;
};
@Input() public set value(value: any) {
if ( value !== undefined ) {
this.writeValue(value);
this.propagateChange(this.innerValue);
this.propagateTouch(true);
}
}
public writeValue(value: any): void {
if (value !== this.innerValue) {
this.innerValue = this.normalize(value);
}
}
}
其中一个自定义控件看起来像这样:
@Component({
selector: 'ultim-checkbox',
encapsulation: ViewEncapsulation.None,
templateUrl: './checkbox-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef( () => CheckboxInputComponent ),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef( () => CheckboxInputComponent ),
multi: true
}
]
})
export class CheckboxInputComponent extends AbstractInputComponent implements ControlValueAccessor, Validator {
constructor ( protected cdr: ChangeDetectorRef ) {
super(cdr);
}
}
然后,在父模板中,我有以下类似的标记:
<ultim-checkbox formControlName="isAdmin"
(change)="setAdmin()"></ultim-checkbox>
但 setAdmin() 方法从未被调用。有任何想法为什么会这样吗?
Angular 11
Typescript 5.1.6
英文:
This was working fine for some time until I found out it wasn't. The issue I face is the following.
I have an abstract value accessor class which is being extended by multiple custom form controls. It looks like this:
@Directive()
export abstract class AbstractInputComponent implements OnChanges {
@Input() public isReadOnly = false;
protected innerValue: unknown = null;
public registerOnChange(fn: any) { this.propagateChange = fn; }
public registerOnTouched(fn: any) { this.propagateTouch = fn; }
public propagateChange = (_: any) => { };
public propagateTouch = (_: any) => { };
public ngOnChanges(): void {
if ( this.isReadOnly ) {
this.propagateChange(this.value);
}
this.cdr.detectChanges();
}
public get value(): any {
return this.innerValue;
};
@Input() public set value(value: any) {
if ( value !== undefined ) {
this.writeValue(value);
this.propagateChange(this.innerValue);
this.propagateTouch(true);
}
}
public writeValue(value: any): void {
if (value !== this.innerValue) {
this.innerValue = this.normalize(value);
}
}
}
One of the custom controls looks like this:
@Component({
selector: 'ultim-checkbox',
encapsulation: ViewEncapsulation.None,
templateUrl: './checkbox-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef( ()=> CheckboxInputComponent ),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef( ()=> CheckboxInputComponent ),
multi: true
}
]
})
export class CheckboxInputComponent extends AbstractInputComponent implements ControlValueAccessor, Validator {
constructor ( protected cdr: ChangeDetectorRef ) {
super(cdr);
}
}
So, then in the big parent template I have this kind of markup:
<ultim-checkbox formControlName="isAdmin"
(change)="setAdmin()"></ultim-checkbox>
And setAdmin() method never gets called. Any ideas why?
Angular 11
Typescript 5.1.6
答案1
得分: 1
问题出在你如何绑定父模板中的 (change) 事件。由于你正在使用 Angular 的响应式表单和 formControlName,正确的事件监听更改的事件是 (ngModelChange) 事件,而不是标准的 (change) 事件。
这是你应该如何修改父模板的方式:
<ultim-checkbox formControlName="isAdmin" (ngModelChange)="setAdmin()"></ultim-checkbox>
英文:
The problem lies in how you're binding the (change) event in the parent template. Since you're using Angular's reactive forms with formControlName, the correct event to listen for changes is the (ngModelChange) event, not the standard (change) event.
Here's how you should modify the parent template:
<ultim-checkbox formControlName="isAdmin" (ngModelChange)="setAdmin()"></ultim-checkbox>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论