Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async custom validation causes an error to the console: "Cannot read property 'required' of null at Object.eval [as updateDirectives]"

Currently, I'm working on an assignment of reactive-forms by Maximilian Schwarzmüller Angular 4 tutorial. In the assignment, I had to create a reactive form, and I did. Then I had to create a custom async validator, that checks the value of the control. It shouldn't be equal to 'Test'. This is my typescript code:

import {Component, OnInit} from '@angular/core';
import {FormControl, FormGroup, Validators} from '@angular/forms';

import {Observable} from 'rxjs/Observable';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  statuses = ['Stable', 'Critical', 'Finished'];
  signupForm: FormGroup;

  ngOnInit() {
    this.signupForm = new FormGroup({
      'projectName': new FormControl(null, [Validators.required], this.forbiddenName),
      'email': new FormControl(null, [Validators.required, Validators.email]),
      'projectStatus': new FormControl('Stable')
    });
  }

  onSubmit() {
    console.log(this.signupForm.value);
    console.log(this.signupForm);
  }

  forbiddenName(control: FormControl): Promise<any> | Observable<any> {
    const promise = new Promise<any>((resolve, reject) => {
      setTimeout(() => {
        if (control.value === 'Test') {
          resolve({'projectNameIsForbidden': true});
        } else {
          resolve(null);
        }
      }, 2000);
    });
    return promise;
  }

}

And here is my html:

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
        <div class="form-group">
          <label for="project-name">Project name</label>
          <input type="text" id="project-name" class="form-control" formControlName="projectName">
          <div class="help-block" *ngIf="!signupForm.get('projectName').valid && signupForm.get('projectName').touched">
            <span *ngIf="signupForm.get('projectName').errors['required']">Can't be empty!<br></span>

            <span *ngIf="signupForm.get('projectName').errors['projectNameIsForbidden']">This name is forbidden!</span>
          </div>
        </div>
        <div class="form-group">
          <label for="email">Email</label>
          <input type="email" id="email" class="form-control" formControlName="email">
          <div class="help-block" *ngIf="!signupForm.get('email').valid && signupForm.get('email').touched">
            <span *ngIf="signupForm.get('email').errors['required']">Can't be blank!<br></span>
            <span *ngIf="signupForm.get('email').errors['email']">Has invalid format!</span>
          </div>
        </div>
        <div class="form-group">
          <label for="project-status">Project Status</label>
          <select id="project-status" class="form-control" formControlName="projectStatus">
            <option *ngFor="let status of statuses">{{ status }}</option>
          </select>
        </div>
        <button class="btn btn-success" type="submit">Submit</button>
      </form>
    </div>
  </div>
</div>

It seems to work fine, it gives me the appropriate error messages in my view, but in the console, I receive an error on every keydown in the projectName control. This is the error:

enter image description here

So, why the error appears? Thanks ahead.

like image 836
Alex Zakruzhetskyi Avatar asked Aug 01 '17 07:08

Alex Zakruzhetskyi


1 Answers

The cause of error is here:

<span *ngIf="signupForm.get('projectName').errors['required']">
   Can't be empty!
</span>

While you are typing errors becomes null, and if you move from field before the async validator has done evaluating, errors will be null, therefore Angular cannot read it. This can be solved using safe navigation operator:

<span *ngIf="signupForm.get('projectName').errors?.required">

But as I prefer to show messages is using hasError, so I would change both validations to this instead:

<span *ngIf="signupForm.hasError('projectNameIsForbidden', 'projectName')">
<span *ngIf="signupForm.hasError('required', 'projectName')">
like image 74
AT82 Avatar answered Nov 14 '22 01:11

AT82