Angular 12 - TypeError: Cannot read properties of null (reading 'writeValue')

25.4k Views Asked by At

Angular 12 - TypeError: Cannot read properties of null (reading 'writeValue')

I'm creating a generic text input component, everything works well while serving the project, but in the built project I get this error:

TypeError: Cannot read properties of null (reading 'writeValue')

HTML:

<div class="p-field">
    <label>{{label}} <span class="p-error">{{checkRequired(ngControl.control) ? '*' : ''}}</span></label>
    <input class="full-width" [type]="type" pInputText [formControl]="ngControl.control">

    <small *ngIf="ngControl.control.touched && ngControl.control.errors?.required" class="p-error">{{label}} is required</small>


    <small *ngIf="ngControl.control.errors?.minlength" class="p-error">
        {{label}} must be at least {{ngControl.control.errors.minlength['requiredLength']}}
    </small>

    <small *ngIf="ngControl.control.errors?.maxlength" class="p-error">
        {{label}} must be at most {{ngControl.control.errors.maxlength['requiredLength']}}
    </small>
    <small *ngIf="ngControl.control.errors?.email" class="p-error">
        This email is not valid
    </small>

    <small *ngIf="ngControl.control.errors?.isMatching" class="p-error">Passwords do not match</small>
</div>

component.ts

import { Component, Input, OnInit, Self } from '@angular/core';
import {AbstractControl, ControlValueAccessor, NgControl} from '@angular/forms';

@Component({
  selector: 'app-text-input',
  templateUrl: './text-input.component.html',
  styleUrls: ['./text-input.component.css']
})
export class TextInputComponent implements ControlValueAccessor {
  @Input() label: string;
  @Input() type = 'text';

  constructor(@Self() public ngControl: NgControl) {
    this.ngControl.valueAccessor = this;
  }

  checkRequired(control) {
    if (control.validator) {
      const validator = control.validator({} as AbstractControl);
      if (validator && validator.required) {
        return true;
      }
    }
  }

  writeValue(obj: any): void {
  }

  registerOnChange(fn: any): void {
  }

  registerOnTouched(fn: any): void {
  }

}

Angular info:

Angular CLI: 12.2.6 Node: 14.17.3 Package Manager: npm 6.14.13 OS: win32 x64 Angular: 12.2.6

9

There are 9 best solutions below

0
On

I got this error when i tried to make the authorsiation check in the backend part of the validation logic. I declared the submit button in the formbuilder group. When I used an input with style="display: none" all was fine.

1
On

Check module.ts. We need to import DropDownsMoudle to user dropdownlists.

import { DropDownsModule } from "@progress/kendo-angular-dropdowns";

0
On

Maybe a bit late but it might help someone here:

I got this error when I attached formControlName to mat-radio-button instead to mat-radio-group.

0
On

In constructor use @Optional() and do null check :

constructor(@Optional() @Self() public ngControl: NgControl) {
   if (this.ngControl != null) this.ngControl.valueAccessor = this;
}

Also, add body to methods like

writeValue(value: number): void {
    this.value = value;
    this.onChange(this.value);
}

onChange: (_: any) => void = (_: any) => {};

onTouched: () => void = () => {};

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

registerOnTouched(fn: any): void {
    this.onTouched = fn;
}
0
On

I would suggest that you create a module called SharedModule, where you will declare all your shared components in the declarations array. in your exports array, export the custom text input component. And then where you need to use the component, import the shared module into your app.module. Remember to remove the input declaration in app.module and only import the sharedModule. Also remember to import the ReactiveFormsModule and the FormsModule in your sharedModule.ts

1
On

In my case, the specific error was appearing because I had not added the specific component in the module imports.

0
On

The error occurs when provider setup is missing

  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi:true,
      useExisting: CUSTOMER_INPUT_CLASS_HERE
    }
  ]  

In your case

@Component({
  selector: 'app-text-input',
  templateUrl: './text-input.component.html',
  styleUrls: ['./text-input.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi:true,
      useExisting: TextInputComponent
    }
  ]
})
export class TextInputComponent implements ControlValueAccessor {
...
}
0
On

Some Time Just close stop the ng server and build it again.

0
On

This same error also reproduces when you use formControlName over any non-input element like <div>. So please make sure to use formControlName attribute over input elements or select to bind the values.

This answer may be helpful for someone looking for the same error.