'this' coming as undefined in Custom Form Validators

I have written the following code:

test.html

<ion-header>
  <ion-navbar>
    <ion-title>faq</ion-title>
  </ion-navbar>
</ion-header>
<ion-content padding>
  <div >
    <h2 >Demo Form: Sku</h2>
    <form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm.value)">

      <ion-item>
          <ion-label floating>SKU</ion-label>
          <ion-input type="text" id="skuInput" name="sku" [formControl]="myForm.controls['sku']"></ion-input>
      </ion-item>

      <ion-card >
        <ion-card-header >
          <ion-label >Q1. Test Question</ion-label> 
        </ion-card-header>

        <ion-list radio-group name="question" [formControl]="myForm.controls['question']">
          <ion-item>
            <ion-label>Yes</ion-label>
            <ion-radio value="true"></ion-radio>
          </ion-item>

          <ion-item>
            <ion-label>No</ion-label>
            <ion-radio value="false"></ion-radio>
          </ion-item>
        </ion-list>
      </ion-card>


      <button ion-button type="submit" round>
        Submit
      </button>
    </form>
  </div>
</ion-content>

test.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { FormControl, FormBuilder, FormGroup, Validators, AbstractControl} from '@angular/forms';

@Component({
  templateUrl: 'test.html',
})
export class TestPage {

  myForm : FormGroup;
  sku: AbstractControl;

  constructor(public nav: NavController,
              public fb : FormBuilder) {
    this.myForm = fb.group({
      'sku': ['', Validators.compose([Validators.required,this.skuValidator])],
      'question' : ['', Validators.required]
    });

    this.sku = this.myForm.controls['sku'];
  }

  onSubmit(value : string): void {
    if(!this.myForm.valid){
      if(this.myForm.controls['sku'].hasError('required')){
        alert('SKU is mendatory.');
        return;
      }
      if(this.myForm.controls['sku'].hasError('invalidSku')){
        alert('SKU is invalid.');
        return;
      }
      if(this.myForm.controls['question'].hasError('required')){
        alert('Question is mendatory.');
        return;
      }
    }
    console.log('you submitted value:', value);
    this.myForm = this.fb.group({
      'sku': ['', Validators.compose([Validators.required,this.skuValidator])],
      'question' : ['', Validators.required]
    });
  }

  skuValidator(control: FormControl): { [s: string]: boolean } {
    if (!control.value.match(/^123/)) {
      alert('Inside skuValidator');
      console.log('value of this :: ' , this);
      return {invalidSku: true};
    }
  }
}

In side the function skuValidator, I am printing the value of ‘this’ but it is coming as undefined. Due to this, i am not able to validate the form against the value which I have to read from the service. Is there something I am doing wrong or it is by default designed this way?

skuValidator is a function, not a method, rigth?
If so, it has its own scope and you need to assign this to an variable before get inside skuValidator

let _this = this
this.myForm = this.fb.group({
      'sku': ['', Validators.compose([Validators.required,this.skuValidator])],
      'question' : ['', Validators.required]
    });


 skuValidator(control: FormControl): { [s: string]: boolean } {
    if (!control.value.match(/^123/)) {
      alert('Inside skuValidator');
      console.log('value of this :: ' , _this);
      return {invalidSku: true};
    }
  }

If you look into the code…its the member method of class TestPage…so by conversion ‘this’ should be available inside skuValidator(). Isn’t it?

If skuValidator() is a method, I assumed that this should keep class context… read this

Typical Symptoms and Risk Factors

Typical symptoms of a lost this context include:

  • A class field (this.foo) is undefined when some other value was expected
  • The value this points to the global window object instead of the class instance (non-strict mode)
  • The value this points undefined instead of the class instance (strict mode)
  • Invoking a class method (this.doBar()) fails with the error “TypeError: undefined is not a function”, “Object doesn’t support property or method ‘doBar’”, or “this.doBar is not a function”
    These things often happen in certain coding patterns:
  • Event listeners, e.g. window.addEventListener(‘click’, myClass.doThing);
  • Promise resolution, e.g. myPromise.then(myClass.theNextThing);
  • Library event callbacks, e.g. $(document).ready(myClass.start);
  • Functional callbacks, e.g. someArray.map(myClass.convert)
  • Classes in ViewModel-type libraries, e.g.
  • Functions in options bags, e.g. $.ajax(url, { success: myClass.handleData })

can you tell me in which place you have written let _this = this ??

1 Like

This is how it works. Custom validators are static, and you can’t rely on this in them.

Agree with @rapropos, but if you really need to do something like this, you can define your function like arrow function. That’s the way to capture this
plunker

Typescript function doc about this

2 Likes

thank you so much, this should be marked as accepted Solution