why is custom validator not working

淺唱寂寞╮ 提交于 2019-12-13 03:34:34

问题


I created a custom Validator called threeNumbers what it does is that it accepts only three digit numbers. But when I applied it to the username field it throws an error ERROR TypeError: Cannot read property 'length' of null and formGroup expects a FormGroup instance. Please pass one in.

  ngOnInit() {
    // form controls validation specicified in the class for the Reactive Forms
    this.courseForm = this.fb.group({
      username: [null, [Validators.required, this.threeNumbers.bind(this)]],
      email: [null, [Validators.required, Validators.pattern('([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+)\\.([a-zA-Z]{2,5})')]],
      address: [null, [Validators.required, Validators.minLength(10), Validators.maxLength(100)]],
      select: [null, [Validators.required]]
    });
    this.dropDownArr = this.dropdown.getData();
    // this.personDetail = {
    //   name: '',
    //   email: '',
    //   address: '',
    //   chosenCourse: ''
    // };
    this.personDetail = this.fieldData.getPersonData();
    console.log(this.courseForm);
  }

  threeNumbers(control: FormControl) {
    if (control.value.length < 3 && typeof control.value !== 'number') {
      return { 'greater than 3 numbers': true };
    }
    return null;
  }

//HTML template

<!-- Form with three inputs and one dropdown which intializes with data from service on intialization and validates with min and maxlength-->
<section class="container">
  <!-- ngSubmit calls the function onSubmit on submitting the form  -->
  <form class="form-horizontal" (ngSubmit)='onSubmit()' [formGroup]='courseForm'>
    <div class="form-group">
      <label for="inputUsername" class="col-sm-2 control-label">Username</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="inputUsername" placeholder="Username" formControlName="username" name="name"
          [ngClass]="{inValid: !courseForm.get('username').valid && courseForm.get('username').touched, valid: courseForm.get('username').valid && courseForm.get('username').touched}">
        <span class="help-block" *ngIf="!courseForm.get('username').valid && courseForm.get('username').touched">Please enter a valid username</span>
      </div>
    </div>
    <!-- username input ends here -->
    <div class="form-group">
      <label for="inputEmail" class="col-sm-2 control-label">Email</label>
      <div class="col-sm-10">
        <!-- CSS class applied based on validation -->
        <input type="email" class="form-control" id="inputEmail" placeholder="Email" formControlName="email" name="email" [ngClass]="{inValid: !courseForm.get('email').valid && courseForm.get('email').touched, valid: courseForm.get('email').valid && courseForm.get('email').touched}">
        <span class="help-block" *ngIf="!courseForm.get('email').valid && courseForm.get('email').touched">Please Enter a valid email</span>
      </div>
    </div>
    <!-- email input ends here -->
    <div class="form-group">
      <label for="inputAddress" class="col-sm-2 control-label">Address</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="inputAddress" placeholder="Your Address" formControlName="address" name="address"
          [ngClass]="{inValid: !courseForm.get('address').valid && courseForm.get('address').touched, valid: courseForm.get('address').valid && courseForm.get('address').touched}">
        <!--Display error message on MinLength and MaxLength Validation-->
        <span class="help-block" *ngIf="courseForm.get('address')?.errors?.required && courseForm.get('address').touched">Please Enter Your Address</span>
        <span class="help-block" *ngIf="(courseForm.get('address')?.errors?.minlength?.requiredLength !== courseForm.get('address')?.errors?.minlength?.actualLength) && courseForm.get('address')?.touched">Address should be at least 10 characters long</span>
      </div>
    </div>
    <!-- address input ends here -->
    <div class="form-group">
      <label for="sel1" class="col-sm-2 control-label">Choose Course</label>
      <div class="col-sm-10">
        <select class="form-control" id="sel1" formControlName="select" [(ngModel)]="selectedOption" name="select" [ngClass]="{inValid: !courseForm.get('select').valid && courseForm.get('select').touched, valid: courseForm.get('select').valid && courseForm.get('select').touched}">
          <option [value]="selectedOption" [disabled]="true">Choose Your Course</option>
          <option *ngFor="let data of dropDownArr; index as i"  [ngValue]="data.course">{{data.course}}</option>          
        </select>
        <span class="help-block" *ngIf="!courseForm.get('select').valid && courseForm.get('select').touched">Please choose a Course</span>
      </div>
    </div>
    <!-- select input ends here -->
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button type="submit" class="btn btn-default" [disabled]=!courseForm.valid>Submit</button>
        <button type="button" class="btn btn-default" (click)="resetForm(f)">Reset</button>
      </div>
    </div>
    <!-- submit and reset buttons ends here -->
  </form>
</section>
<!-- section displays the submited form data in the view -->
<section class="container">
  <div class="panel panel-default">
    <div class="panel-heading">Registered users</div>

    <!-- List group -->
    <ul class="list-group">
      <li class="list-group-item" *ngFor="let person of personsList">username:&nbsp;&nbsp;{{person.name}} &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp; email:&nbsp;&nbsp;{{person.email}}
        &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp; Address: &nbsp;&nbsp;{{person.address}} &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;
        Course Chosen: &nbsp;&nbsp;{{person.chosenCourse}}</li>
    </ul>
  </div>
</section>

回答1:


Like the built-in validators, you do not need to call threeNumbers, just pass it as a reference to this.fb.group:

You do not need the bind call, as Angular calls this internally. Change it to:

this.courseForm = this.fb.group({
  username: ['', [Validators.required, this.threeNumbers]],
  email: ['', [Validators.required, Validators.pattern('([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+)\\.([a-zA-Z]{2,5})')]],
  address: ['', [Validators.required, Validators.minLength(10), Validators.maxLength(100)]],
  select: ['', [Validators.required]]
});

At the moment, you're binding the this property. In this instance, this refers to your instantiated version of the class.

Remove the parenthesis essentially.

You could go the extra mile and make your threeNumbers method static since a validator should not depend on any local variables - the Angular default validators are static.

public static ThreeNumbers(control: FormControl) {
  if (control.value.length < 3 && typeof control.value !== 'number') {
    return { 'greater than 3 numbers': true };
  }
  return null;
}

I would also recommend passing an empty string '', instead of null to each control initialisation. This helps with a consistent state. N.b. on that note, you have a 'typeof' check, if this FormControl is bound to an input, then typeof will always be a string.

I have made amends - see above.



来源:https://stackoverflow.com/questions/46447270/why-is-custom-validator-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!