Home > Mobile >  this.onChange is not a function when using ControlValueAccessor in Angular Reactive Form
this.onChange is not a function when using ControlValueAccessor in Angular Reactive Form

Time:04-12

I am using ControlValueAccessor to pass data between a child component and a parent which works as expected but when I initialize the component I get always the error

ERROR TypeError: this.onChange is not a function

After that the code works as expected and the values are past from the Child componenet to parent correctly. The section of my code that threows the error is this.onChange(formData.selectField) after I subscribe to the change event. Sio not sure what causes this error and how to get rid of it. I have a feeling that the onChange function is not registered when i try to call it or something like that extend

import {
  Component,  forwardRef,  Input,  OnInit,  AfterViewInit} from '@angular/core';
import {  AbstractControl,  ControlValueAccessor,  FormControl,  FormGroup,  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,  Validators,} from '@angular/forms';
import { Button } from '../models/button.model';

@Component({
  selector: 'app-button-toggle',
  templateUrl: './button-toggle.component.html',
  styleUrls: ['./button-toggle.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ButtonToggleComponent),
      multi: true,
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => ButtonToggleComponent),
      multi: true,
    },
  ],
})
export class ButtonToggleComponent
  implements ControlValueAccessor, OnInit, AfterViewInit
{
  @Input() guid: string;
  @Input() isRequired = false;
  @Input() multiSelect = true;

  private _disabled = false;

  value;
  selectField;
  form: FormGroup;
  onChange: Function;
  onTouched: Function;
  validateFn: Function;
  @Input() trackOptions: Button[];

  constructor() {}
  ngAfterViewInit() {
    console.log('After View Init');
    this.getInitialChecked();
  }

  registerOnChange(fn: (value: any) => void) {
    this.onChange = fn;
  }

  ngOnInit() {
    this.selectField = new FormControl(this.value, []);
    this.form = new FormGroup({
      selectField: this.selectField,
    });
    if (this.isRequired) {
      this.form.get('selectField').setValidators(Validators.required);
      this.form.get('selectField').updateValueAndValidity();
      this.form.updateValueAndValidity();
    }

    this.form.valueChanges.subscribe((formData) => {
      this.onChange(formData.selectField);
      this.value = formData.selectField;
    });
  }

  writeValue(value) {
    console.log(value);
    this.value = value;
    this.form.get('selectField').setValue(this.value);
  }

  validate(c: FormControl) {
    //return this.validateFn(c);
  }

  registerOnTouched(fn: () => void) {
    this.onTouched = fn;
  }
  onValChange(e: number, b: boolean) {
    if (b === true) {
        this.setCheckedButton(e);
   
    } else {
      this.setUncheckedButton(e);
    }
  }

CodePudding user response:

registerOnChange method is called after writeValue. In write value you're updating your form.

While it's okay to set value for FormControl within writeValue method but it's useless to listen to valueChanges at that point because value comes from consumer and we don't need to notify about it back.

So, try not to fire valueChanges event within writeValue by using emitEvent option:

this.form.get('selectField').setValue(this.value, { emitEvent: false });
                                                  ^^^^^^^^^^^^^^^^^^^^^
  • Related