Search code examples
angulartypescriptangular-materialangular-controlvalueaccessor

No value accessor error when using mat-slide-toggle


I'm using angular reactive forms, the form group is initialized in the parent component and form controls are located in the child components.

The problem is that I getting the following error message when I access the page:

ERROR Error: No value accessor for form control with unspecified name attribute

For testing purpose, I tried to replace mat-slide-toggle with input checkbox and the error goes away, why is it complaining with slider, I can't understand.

Here's similar example:

Parent Module

@NgModule({
    ...
    declarations: [ParentComponent],
    imports: [
        ...,
        MatSlideToggleModule,
    ]
})
export class ParentModule {}

Parent Component

@Component({
    selector: 'app-parent',
    template: `
        <form [formGroup]="myFormGroup">
            <app-child-a [subscribedControl]="$any(myFormGroup.controls.myOption)"></app-child-a>
        </form>
    `
})
export class ParentComponent {
    public myFormGroup: FormGroup = this._fb.group({
        myOption: [true, [Validators.required]],
    });

    constructor(private _fb: FormBuilder) {}
}

Child A Component

@Component({
    selector: 'app-child-a',
    template: `
        <mat-slide-toggle [formControl]="subscribedControl"></mat-slide-toggle>
    `
})
export class ChildAComponent {
    @Input() public subscribedControl!: FormControl;
}

Any ideas?


Solution

  • Based on what you provided and considering this is not the original snippet, here are a few things to check:

    1. Are you declaring your child component in your ParentModule? Or are you importing the appropriate module that contains it? Cause in the provided snippet you don't. (This would probably generate a different error though)
    2. Are you using the "reserved" name formControl as your child's input property name? If so change it to something else. E.g. @Input() control: FormControl.

    On another note, passing the form control itself isn't an elegant solution.

    If you want to use your ChildComponent as a reusable custom form control, then your component needs to implement the ControlValueAccessor interface and provide it as such.

    This way you're basically saying to Angular: "look my custom control follows the rules that every other native form element follows. So you can use it in the form."

    If you implement this interface and provide your component as a CVA, then you don't need to pass the form control.

    You can read a detailed explanation in this article.

    Alternatively, if you simply need to break the form into sub-form components and don't care for re-usability & portability, then you can use this approach.