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
The problem lies in how you're binding the
(change)event in the parent template. Since you're using Angular's reactive forms withformControlName, 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: