What is the best way to retrieve the input field's name using an Angular2 FormControl object?

My Angular 2 application features the ReactiveForms module for managing a form with its own custom validator. This validator takes in a FormControl object as an input parameter. I've noticed that multiple input fields could benefit from using this same custom validator if only there was a way to determine the field's name when passing the FormControl to the validator.

I've searched extensively but haven't been able to find any method or public property within the FormControl that exposes the name of the input field. While it's easy to access the value, retrieving the field's name seems to be the missing piece of the puzzle. The code snippet below demonstrates how I envision utilizing this functionality:

public asyncValidator(control: FormControl): {[key: string]: any} {
  var theFieldName = control.someMethodOfGettingTheName(); // this is where I need help

  return new Promise(resolve => {
      this.myService.getValidation(theFieldName, control.value)
        .subscribe(
          data => {
            console.log('Validation success:', data);
            resolve(null);
          },
          err => {
            console.log('Validation failure:', err);
            resolve(err._body);
          });
    });
  }

Answer №1

In addition to Radim Köhler's response, here is a more concise version of the function:

getControlName(c: AbstractControl): string | null {
    const formGroup = c.parent.controls;
    return Object.keys(formGroup).find(name => c === formGroup[name]) || null;
}

Answer №2

The property .parent can be utilized, and today we can also use ["_parent"] (further details below):

export const getControlName = (control: ng.forms.AbstractControl) =>
{
    var controlName = null;
    var parent = control["_parent"];

    // Only a parent that is a FormGroup has a dictionary 
    // with control names as keys and form controls as values
    if (parent instanceof ng.forms.FormGroup)
    {
        // We will now iterate through those keys (control names)
        Object.keys(parent.controls).forEach((name) =>
        {
            // Compare the passed control with 
            // a child control of the parent using the provided name (iterating through all)
            if (control === parent.controls[name])
            {
                // Both are the same: the control passed to the Validator
                //  and this child have the same references
                controlName = name;
            }
        });
    }
    // Return the control name or null if not found
    return controlName;
}

We are now set to update our validator definition

public asyncValidator(control: FormControl): {[key: string]: any} {
  //var theFieldName = control.someMethodOfGettingTheName(); // This part is missing
  var theFieldName = getControlName(control); 
  ...

.parent: then vs. ["_parent"]: now

As of now (today), the current release is :

2.1.2 (2016-10-27)

However, according to this issue: feat(forms): make 'parent' a public property of 'AbstractControl'

And as mentioned in

2.2.0-beta.0 (2016-10-20)

Features

  • forms: make 'parent' a public property of 'AbstractControl' (#11855) (445e592)
  • ...

We may switch from using ["_parent"] to .parent in the future

Answer №3

To configure the control name in validators, follow these steps:

this.form = this.fb.group({
     controlName: ['', 
         [
            Validators.required, 
            (c) => this.validate(c, 'controlName')
         ]
      ]
});

Next, create the validation function:

validate(c: FormControl, name) {
    return name === 'controlName' ? {invalid: true} : null;
}

Answer №4

Starting from Angular version 4.2.x, you have the ability to retrieve the parent FormGroup (along with its controls) of a FormControl by using the public parent property:

private formControl: FormControl;

//...

Object.keys(this.formControl.parent.controls).forEach((key: string) => {
  // ...
});

Answer №5

There are two paths you can take:

By utilizing the Attribute decorator:

constructor(@Attribute('formControlName') public formControlName) {}

Or by using the Input decorator:

@Input() formControlName;

Keep in mind that for this to work, your validation needs to function as a directive.

Answer №6

This revised solution presents a simplified version of the initial answer and fixes the bug mentioned in the comment.

retrieveControlName(control: FormControl): string | null {
  return Object.entries(control.parent?.controls ?? []).find(([_, value]) => value === control)?.[0] ?? null;
}

Answer №7

It may not be the exact solution you're looking for, but one option is to dynamically generate the validator as shown in some sample codes.

For example:

typeBasedValidator(controlName: string): ValidatorFn {
  return(control: AbstractControl): {[key: string]: any} => {
     // Your validation logic using controlName
     if(controlName == "something") { 
       doSomething(); 
     } else { 
       doSomethingElse(); 
     }
  }
}

You can then apply this validator when creating the form by specifying the control name.

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

What is GraphQl indicating when it informs me that I neglected to send arguments for the mutation

My GraphQL schema consists of various mutations and queries. I believe that validation of mutations should only occur when I send mutation { ... } to the graphql server. However, currently, the server is informing me that I have not sent arguments for all ...

What is the best approach for integrating QuadraticBezierCurve3 as the geometry for Three.Line2 in Typescript and r3f?

I'm in the process of rendering curved arcs between two points on a 3D sphere representing the Globe. I've managed to create arcs using Three.Line as shown below: const calculatePositionFromLatitudeLongitudeRadius = (latitude: number, longitude: ...

The npm lint command is throwing an "Observable `source is deprecated`" error

When I execute the command npm lint on my code, I receive a warning stating "source is deprecated: This is an internal implementation detail, do not use." The specific part of the code causing this issue is shown below: set stream(source: Observable<a ...

Identifying the origin of the error (whether it's from the client or the server) within

I am utilizing ngrx effect for handling user login in my application: @Effect() authLogin = this.actions$.pipe( ofType(LOGIN_START), switchMap(() => this.http.post('/user/login') .pipe( catchError( (response) => ...

Arranging Objects in Angular 2 using Pipes

While I've come across similar questions, none of the solutions provided have worked for me so far. Therefore, please refrain from marking this as a duplicate unless you can point me to an answer that actually resolves my issue. Currently, I am worki ...

Modifying tooltip format in React ApexChart from dots to commas

I am in the process of creating an app targeted towards German users, who traditionally use commas (20,00) instead of dots (20.00) for numbers. I am using react-apexcharts and struggling to figure out how to replace the dots with commas in both my chart an ...

Exploring Angular 2: Best Practices for Debugging Objects and Looping Through Them

After successfully fetching the API data from , it appears that everything is set up correctly. The next step is to display the menu children from the API object.items. However, when I try to use {{ menus }}, all I get is [object object]. It seems that us ...

When another page is refreshed, Angular routing redirects back to the home page

Within my application, there is a homepage that appears after the user logs in, along with some other pages. However, I've encountered an issue where when I navigate to one of these other pages and then refresh the page, it redirects me back to the ho ...

Toggle visibility of layers in ngx-mapboxgl

As I delve into ngx-mapboxgl, it becomes apparent that the documentation is lacking. My goal is to construct a layer with markers that can be toggled on and off. Despite following an example from the web, I encounter a runtime error claiming it cannot loca ...

Best practices for utilizing forwardRef and next/dynamic in next.js version 13.4 with the "react-email-editor" component

I've been attempting to utilize the "react-email-editor" library in a Next.js project. My goal is to copy the email content generated within the editor to the clipboard. Since the library relies on browser interaction and the use of the "window" objec ...

Facing the issue of "Protractor not syncing with the page" while trying to navigate an Angular website

I'm currently attempting to follow the tutorial for Protractor on the official Protractor website, but I've hit a roadblock at step 0. My setup involves using protractor and webdriver-manager version 6.0.0. I am running Linux (Ubuntu 18.06) as m ...

Testing abstract class methods in Jest can ensure full coverage

In my project, I have an abstract generic service class. export default abstract class GenericService<Type> implements CrudService<Type> { private readonly modifiedUrl: URL; public constructor(url: string) { this.modifiedUrl = ...

Leverage TypeScript AngularJS directive's controller as well as other inherited controllers within the directive's link function

I am currently developing an AngularJS directive in TypeScript for form validation. I am trying to understand how to utilize the directive's controller and inherit the form controller within the directive's link function. Thank you in advance! ...

On iOS devices, the confirm/cancel alert box in Ionic v3 does not display in the center as expected

Encountering an issue with Ionic v3 where the alert box appears at the top only when a text box is included within it. This behavior is observed on regular devices like iPhones, but functions correctly on Android devices. Other form elements like checkboxe ...

Inference of generic types within a TypeScript generic

In my coding journey, I came across a situation where I was dealing with generic classes. Specifically, I had a Generic class Generic<T> and another one called GenericWrap that used Generic as its maximum type parameter (denoted as U extends Generic& ...

Cancel the previous Angular/RxJS request to unsubscribe

I'm on the quest for a more streamlined approach using RxJS to tackle this task. The existing code gets the job done, but it seems like there should be a more efficient solution. ngOnInit() { this.activatedRoute.params.subscribe(({ bookId }) => ...

Implementing Reddit API with Single Page Application using Implicit Grant flow strategy

Whenever I try to redirect to https://www.reddit.com/api/v1/authorize?response_type=token&client_id=3JTVJFUn28MxFQ&state=RANDOMSTATEFORCONFIRMATION&redirect_uri=http%3A%2F%2Flocalhost%3A4200&scope=read from my Angular application, I encou ...

What are the steps to transpile NextJS to es5?

Is it possible to create a nextjs app using es5? I specifically require the exported static javascript to be in es5 to accommodate a device that only supports that version. I attempted using a babel polyfill, but after running es-check on the _app file, ...

Jest encountered an UnhandledPromiseRejection error because the promise was unexpectedly resolved instead of being rejected

I am facing a difficult error message from Jest that I can't seem to figure out. The error message indicates that the promise is being resolved instead of rejected, causing an unhandled promise rejection. It's confusing because Jest expects an er ...

Encountering the error "bash: typeorm: command not found" post installation of typeorm globally on a linux system

Operating System: Running macOS Sierra v 10.12.6 This is my first experience using Typescript and typeorm as I attempt to develop an application. I have tried both of the following commands to install typeorm: npm i -g typeorm & sudo npm i -g type ...