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

10

11

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

Bellebelleek answered 3/10, 2021 at 11:52 Comment(1)
for me the error occured because i had the "[(ngModel)]="email" in the button html tag instead of the input facepalmBismuthous
V
15

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

Volvox answered 23/6, 2022 at 9:31 Comment(1)
Thanks for your comment. I had the exact same issue and you probably just saved me like an hour!!Oliana
S
7

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 {
...
}
Settera answered 20/2, 2022 at 10:0 Comment(0)
B
6

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.

Branle answered 24/11, 2022 at 10:6 Comment(0)
Q
4

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.

Quite answered 31/3, 2023 at 7:16 Comment(0)
A
0

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.

Alister answered 5/5, 2022 at 11:38 Comment(0)
I
0

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

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

Insubordinate answered 15/1, 2023 at 0:58 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Damato
W
0

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

Whirligig answered 1/2, 2023 at 23:11 Comment(0)
O
0

I was using Reactive Forms. This happened when I was attaching formControlName to my child component, which we should not. Though, it should have been done within the callback function say (onSelectionChange)="handler()" then inside handler() you should do patchValue as below:

(this.FormName.get('sayList') as FormArray).at(index).get('keyName').patchValue(assignValue);

Note: list of items and have used FormArray.

Officialdom answered 2/7 at 13:40 Comment(0)
P
-1

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;
}
Pupil answered 3/10, 2021 at 12:19 Comment(0)
G
-1

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

Gaultheria answered 23/2 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.