'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 ??

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

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