Angular 4 - validator custom function this is undefined
Asked Answered
T

3

18

I'm building an app with component FormComponent. inside I'm using reactive forms module from angular core and create a custom validator. the function is calling another function by using this - as I supposed it will refer to the FormComponent, but it refers to be 'undefined' (?)

The code in onInit defines the FormGroup and FormControl and outside of it defines the functions

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  formInsurance:FormGroup;
  private id:FormControl;


  constructor(){}


  ngOnInit() {

    this.id = new FormControl('',[
      Validators.required,
      Validators.minLength(3),
      Validators.maxLength(10),
      Validators.pattern('^[0-9]+(-[0-9]+)+$|^[0-9]+$'),
      this.foo
    ]);


    this.formInsurance = new FormGroup({
      id:this.id      
    })


  }


  foo(control:FormControl){
  this.boo();
  if(control.value){
    return {
      objToReturn: {
          returned: name
      }
    };
  }
  return null
}

boo(){
  console.log('boo')

}

}

Tagliatelle answered 14/2, 2018 at 10:52 Comment(2)
It's written outside onInit, but I guess it is called on the onInit scope because this is when the form control validators initialTagliatelle
yes sorry , i have just seen itPeggi
U
30

The context in the foo method when called from within the FormControl is not referencing the FormComponent.

You can do the following to fix this behavior using bind to set the context yourself:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  formInsurance:FormGroup;
  private id:FormControl;


  constructor(){}


  ngOnInit() {

    const id = new FormControl('',[
      Validators.required,
      Validators.minLength(3),
      Validators.maxLength(10),
      Validators.pattern('^[0-9]+(-[0-9]+)+$|^[0-9]+$'),
      this.foo.bind(this)
    ]);

    this.id = id;

    this.formInsurance = new FormGroup({
      id
    })
  }


  foo(control:FormControl) {
    this.boo();
    if(control.value){
        return {
          objToReturn: {
              returned: name
          }
        };
      }
    return null
  }

  boo(){
    console.log('boo')

  }
}
Uni answered 14/2, 2018 at 11:5 Comment(1)
Thank you! This was annoying to deal with.Rachellerachis
L
12

And of course, the other alternative is the arrow function, which auto-binds to the this context:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, ValidationErrors } from '@angular/forms';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  formInsurance:FormGroup;
  private id:FormControl;

  constructor() {}

  ngOnInit() {
    this.id = new FormControl('',[
      Validators.required,
      Validators.minLength(3),
      Validators.maxLength(10),
      Validators.pattern('^[0-9]+(-[0-9]+)+$|^[0-9]+$'),
      this.foo
    ]);

    this.formInsurance = new FormGroup({
      id:this.id      
    })
  }

  foo = (control: FormControl): ValidationErrors => {
    this.boo();
    if (control.value) {
      return {
        objToReturn: {
          returned: name
        }
      };
    }
    return null
  }

  boo() {
    console.log('boo')
  }
}
Lir answered 12/9, 2019 at 19:30 Comment(1)
Thanks!! This helped me when this.foo.bind(this) didn't work.Plataea
P
0

You can return the needed function, take what you want from this as a parameter and return the function that you want. That way it's cleaner because often times you'd only need one value from this

in you example, it would look like this:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  formInsurance: FormGroup;
  private id: FormControl;


  constructor() { }

  ngOnInit() {

    this.id = new FormControl('', [
      Validators.required,
      Validators.minLength(3),
      Validators.maxLength(10),
      Validators.pattern('^[0-9]+(-[0-9]+)+$|^[0-9]+$'),
      this.foo(this.boo)
    ]);


    this.formInsurance = new FormGroup({
      id: this.id
    })
  }

  foo(boo) {
    return (control: FormControl) => {
      boo();
      if (control.value) {
        return {
          objToReturn: {
            returned: name
          }
        };
      }
      return null
    }
  }

  boo() {
    console.log('boo')
  }
Pickpocket answered 27/3, 2023 at 21:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.