英文:
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论