Angular 4 - custom validator function not properly defined

I am currently developing an application that includes a FormComponent. Within this component, I am utilizing the reactive forms module from Angular core to create a custom validator. When calling a function from within another function using 'this', I expected it to refer to the FormComponent, but instead, it is showing as 'undefined' (?).

In the code block under onInit, the FormGroup and FormControl are defined, while functions are declared outside of it.

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');
  }

}

Answer №1

When the foo method is executed within the FormControl, it does not refer to the FormComponent.

To resolve this issue, you can utilize bind to set the context manually:

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

  }
}

Answer №2

One option to consider is utilizing the arrow function, as it automatically binds to the current 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.customValidation
    ]);

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

  customValidation = (control: FormControl): ValidationErrors => {
    this.performAction();
    if (control.value) {
      return {
        validationObj: {
          returnedValue: name
        }
      };
    }
    return null
  }

  performAction() {
    console.log('custom action')
  }
}

Answer №3

To achieve the desired functionality, you can create a function that returns the specific function you need by passing in parameters from 'this'. This approach helps keep your code clean and concise since you may only require one value from 'this'.

For instance, the implementation would resemble the following:

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.customFunction(this.example)
    ]);

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

  customFunction(example) {
    return (control: FormControl) => {
      example();
      if (control.value) {
        return {
          objToReturn: {
            returnedValue: name
          }
        };
      }
      return null;
    }
  }

  example() {
    console.log('example')
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Struggling to decide on the perfect CSS selector for my puppeteer script

I am trying to use puppeteer page.type with a CSS selector. <div class="preloader"> <div class="cssload-speeding-wheel"></div> </div> <section id="wrapper" class="login-register"> <div class="login-box"> <d ...

Looking for a comprehensive calculation that takes into account various input values?

I need to display the List Price at the bottom of the form so users are aware of the cost to list their item. Within a php file, I have defined price brackets. For example, if the listing price is £150.00, it falls between £100 and £199.99 and thus nee ...

Struggling with resizing a webcam feed to fit the dimensions of the iframe container?

I'm facing a challenge embedding a camera feed into a webpage that needs to display manual focus and servo controls. The issue lies in the content scaling within the iframe. Even though the iframe boundary resizes according to the window's width ...

The process of selecting particular words from a data-attribute value

Is it possible to extract specific words from a data attribute in a web application while preserving spaces? I am looking to: Select the first word Select the last word Select the word that precedes... Select the word that follows... Select everything t ...

Is it possible for me to link to a local constant file using an href attribute within a link tag?

I am trying to use an SVG icon as the icon for the browser title bar. const svgIcon = <svg class="svg-icon" viewBox="0 0 20 20"> <path "something"></path> </svg> and then I have a link tag that ...

Is it possible to manipulate a Three.js scene using mouse scroll?

Is it possible to synchronize the movement of animated objects in a scene with the mouse scroll? I envision a scenario where objects move within a scene, and their motion is directly tied to the distance calculated by .scrollTop().</h2> The ideal e ...

What is the best way to empower additional controls as a user enters text into a box, but disable them once the text is deleted or the box is left empty

I'm attempting to dynamically enable or disable a set of controls based on the input from a text box. When the user inputs a value into the text box, the controls should be enabled; conversely, if the user deletes the value or leaves it empty, the con ...

Encountering a 400 error when attempting to make a

After recently starting to use angular5, I encountered an error when attempting to insert a new row of data into a table. The error message was Failed to load resource: the server responded with a status of 400 (Bad Request) I've experimented with bo ...

What is the best way to ensure that any modifications made to an item in a table are appropriately synced

Utilizing xeditable.js, I am able to dynamically update the content of a cell within a table. My goal is to capture these changes and send them via an HTTP request (PUT) to the backend in order to update the database. Below is the table that can be edited ...

Is it possible to use Postman to automatically generate request body based on Runner input file?

I rely on Postman for sending requests to a Kanban API, but the data varies each time. For instance, the request body always includes an ID for the Kanban card to be placed on the board, {{External_Card_ID}}, but it may not always include a plannedFinish ...

Using angular.forEach and console.log to iterate over arrays in AngularJS can lead to unexpected results

This application is designed for guessing zip codes, using FireBase and Angular technologies. Whenever the user inputs a digit, a query is sent to a FireBase database which returns an array of zip codes containing that specific digit in the corresponding p ...

Table sorting parser that does not recognize div elements

I'm experiencing an issue with the tablesorter extension on my webpage. All my tables are working correctly except for one that contains a numeric value along with a div element. The problem arises because the tablesorter treats the content as text, c ...

Ways to incorporate an image inside renderCell when printing the MUI X data-grid

Using MUI X data-grid, I have created a grid to display data with the help of renderCell. My goal is to print the data grid and have the image from the first renderCell displayed prominently. const columns: GridColDef[] = [ { field: 'p ...

Most efficient method for accessing and changing the value stored within a BehaviorSubject

I've come across advice stating that using the getValue() method on a BehaviorSubject should be avoided, so I'm curious about the best way to read and update one. Here is the source of this information. In my specific scenario, I have a Behavior ...

What is the reason behind the error Generic indexed type in Typescript?

Here is a scenario where I have a specific generic type: type MapToFunctions<T> = { [K in keyof T]?: (x: T[K]) => void; }; It functions correctly in this instance: type T1 = { a: string }; const fnmap1: MapToFunctions<T1> = { a: (x: st ...

ReactJS: The render method is not updating the style value according to the props

We are currently working on a WordPress builder using ReactJS and have come across an unusual issue. In the screenshot provided, there is a wrapperStyle object containing some CSS styling. The expectation is that the styling should dynamically change b ...

What could be causing my Link to malfunction in my about.js file?

I've encountered an issue where clicking the link in my app doesn't produce any result, and I'm unsure of the cause. Below is the content of my app.js file: import './App.css'; import {BrowserRouter as Router, Routes, Route} from ...

Is there a way to conduct a test on google.maps.Geocoder?

Greetings! I'm in the process of creating a "simple" test to verify a state change in a react class component. Specifically, I want to determine if the lat(latitude) and lng(longitude) states are modified when Google successfully geocodes an address t ...

Is there a way to selectively download a single Angular Material component without needing to download the entire library?

For my current project, I am utilizing Angular Material specifically for the DatePicker component. I am working with the most recent version of Angular. Is it necessary to download the entire Angular Material library, or can I just download the DatePicker ...

Subscribing to events in Angular 2 after switching tabs and returning to the

I have a Subject service implemented as follows; private subject = new Subject<any>(); sendMessage(message: any) { this.subject.next(message); } clearMessage() { this.subject.next(); } getMessage(): Observable<any> { return this ...