Access FormControl inside custom Angular Component

controlvalueaccessor
angular custom form control change event
custom control in angular 7
angular custom component
angular test custom form control
form control angular
formcontrolname for custom component
angular reactive forms set value

I'm creating a custom angular component which shows an error tooltip when my FormControl (Reactive Forms) is invalid. But I don't know how I can access the FormControl inside my custom component to check whether or not it is marked as valid.

What I want to accomplish

<div [formGroup]="form">
     <input formControlName="name" type="text" />
     <custom-validation-message formControlName="name">My special error message!</custom-validation-message>
  </div>

as I get you point you just want to make a componnet for display form control validation message the other answer explane why ControlValueAccessor is not the case here ,you just want to pass a control form reference to the component then check the validation state , Thomas Schneiter answer is a correct why but I face the case and it 's hard to keep get refrance by get method and sometime we are in sub group and form array so I idea is to just pass the name of the form control as string then get the control reference.

CustomValidationMessageComponent

@Component({
  selector: "custom-validation-message",
  templateUrl: "./custom-validation-message.component.html",
  styleUrls: ["./custom-validation-message.component.css"]
})
export class CustomValidationMessageComponent {
  @Input()
  public controlName: string;

  constructor(@Optional() private controlContainer: ControlContainer) {} 

  get form(): FormGroup {
    return this.controlContainer.control as FormGroup;
  }

  get control(): FormControl {
    return this.form.get(this.controlName) as FormControl;
  }
}

template

<ng-container *ngIf="control && control?.invalid && control?.touched">
  <ul>
    <li *ngIf="control.hasError('required')">
      this is required field
    </li>
    <li *ngIf="control.hasError('pattern')">
      pattern is invalid 
    </li>
    <li *ngIf="control.hasError('maxlength')">
      the length is over the max limit
    </li>
     <!-- <li *ngFor="let err of control.errors | keyvalue">
       {{err.key}}
     </li> -->
  </ul>

</ng-container>

and you can use it like this

<form [formGroup]="form">
 <label>
   First Name <input type="text" formControlName="firstName" />
   <div>
       <custom-validation-message controlName="firstName"></custom-validation-message>
   </div>
 </label>

 ...

</form>

demo 🚀🚀

you can check this angular library ngx-valdemort created by JB Nizet where it solve this problem perfectly 👌.

Get access to FormControl from the custom form component in Angular, This solution was born from the discussion in the Angular repository. Please, make sure to read it or even better to participate if you are� Besides, passing the FormControl object to the custom input would give you access to the properties of it without referencing the FormGroup and then getting the specific control, because that's a work done on the parent component.

If i understand you correctly, the <custom-validation-message> should just display validation errors of a reactive forms input.

A ControlValueAccessor is used to create a custom input. What you want to do is to create a simple component with an Abstract control as input. The component could look like this:

ts:

@Input() public control: AbstractControl;
...

With this, you can access the formControls properties like invalid, touched and errors inside of the custom component. html:

<ng-container *ngIf="control?.invalid && control?.touched">
  <ul>
    <li class="validation-message" *ngFor="let error of control.errors">
      {{error}}
    </li>
  </ul>
</ng-container>

then add the control that should display errors as an input

<custom-validation-message [control]="form.get('name')"></custom-validation-message>

Angular Custom Form Control. If you are working on an Angular app , If we just use a custom FormControl only once in the app, it probably time, it's probably a good idea to create a custom component that we can reuse. of ngControl to have access to the FormControl provided in the parent,� Awesome, our custom form control is now ready to be used! Using it inside template-driven forms. We’ve already seen that the counter component works as intended, but now we want to put it inside an actual form and make sure it works in all common scenarios. Activating form APIs

Didn't check your approach. A CustomControlValueAccessor should only be used for real form controls. It's a creative approach, it may works somehow, but I wouldn't go for it.

There are other ways than injection to access the FormControl inside your validation component:

1) Define the FormGroup without the FormBuilder so that you'll have access to the form controls directly:

  firstName: new FormControl('');
  lastName: new FormControl('');

  profileForm = new FormGroup({
    firstName,
    lastName
  });

Then in your html you can pass the form control to the custom-validation-message:

<custom-validation-message [control]="firstName">My special error message!</custom-validation-message>

2) Use the FormBuilder nevertheless, but with a getter function:

// component

get firstName() {
    return this.profileForm.get('firstName') as FormControl;
}
<custom-validation-message [control]="firstName">My special error message!</custom-validation-message>

3) or as Thomas Schneiter wrote: access the control in the template with:

<form [formGroup]="form">
   <input formControlName="name" type="text" />
   <custom-validation-message [control]="form.get('firstName)">My special error message!</custom-validation-message>
</form>

How to manage reactive form controls with form groups in Angular 8 , We explain how you can divide form controls by form groups in Angular 8, providing a platform to easily access the template element as groups. Angular FormControl is an inbuilt class that is used to get and set values and validation of the form control fields like <input> or <select>. The FormControl tracks the value and validation status of an individual form control. It can be used standalone as well as with a parent form. Types of Angular Forms

Here is how you can access the FormControl of a custom FormControl component (ControlValueAccessor). Tested with Angular 8.

<my-text-input formControlName="name"></my-text-input>
@Component({
  selector: 'my-text-input',
  template: '<input
    type="text"
    [value]="value"
  />'
})
export class TextInputComponent implements AfterContentInit, ControlValueAccessor {

  @Input('value') value = '';

  // There are things missing here to correctly implement ControlValueAccessor, 
  // but it's all standard.

  constructor(@Optional() @Self() public ngControl: NgControl) {
    if (ngControl != null) {
      ngControl.valueAccessor = this;
    }
  }


  // It's important which lifecycle hook you try to access it.
  // I recommend AfterContentInit, control is already available and you can still
  // change things on template without getting 'change after checked' errors.
  ngAfterContentInit(): void {
    if (this.ngControl && this.ngControl.control) {
      // this.ngControl.control is component FormControl
    }
  }
}

FormControlName, Syncs a FormControl in an existing FormGroup to a form control element by name. The name in the form of a string is useful for individual forms, while the� So, inside registerOnChange we simply save the reference to the callback fn function passed by formControl. We will trigger it every time the editor content changes. Inside the writeValue method we set the content to the rich editor. And finally, inside registerOnTouched we save the reference to the callback fn function passed by formControl.

Custom form field control, It is possible to create custom form field controls that can be used inside ControlValueAccessor so that your component can work with formControl and� When creating forms in Angular, sometimes you want to have an input that isn’t a standard text input, select, or checkbox. By implementing the ControlValueAccessor interface and registering the component as a NG_VALUE_ACCESSOR, you can integrate your custom form control seamlessly into template driven or reactive forms just as if it were a native input!

FormArrayName, The name in the form of a string is useful for individual forms, while the numerical import {Component} from '@angular/core'; import {FormArray, FormControl,� Angular uses directives to match these attributes with validator functions in the framework. Every time the value of a form control changes, Angular runs validation and generates either a list of validation errors that results in an INVALID status, or null, which results in a VALID status.

Angular 4 Forms: Nesting and Input Validation, Forms in Angular applications can aggregate the state of all inputs that are under have a fully functioning Angular 4 form with access to the form in the component. Angular 4 offers an interface that each custom validator must implement, the FormControl, Validator, ValidationErrors } from '@angular/forms '; @Directive({� It provides a connection (to update values or other needs) between the form control behavior of your custom input and the UI you are providing for that custom form control. Below is the code of a custom input component in TypeScript.

Comments
  • I've just tried out your approach and it works great. I am updating my own framework and ngx-valdemort gave me another idea. Having one container with all the possible errors inside is way better than having to duplicate the custom-validation-message for each possible error.
  • How is that @Optional() private controlContainer: ControlContainer injected? Is that automatically happening inside of the formGroup?
  • @ThomasSchneiter the ControlContainer inject by angular and give us access to the formGroup instance from the parent check this and include a talk by Kara Ericksons thecodecampus.de/blog/nested-forms-in-angular
  • hi 👋, control.errors is an object of key value not any array so this case you will get an error like this NgFor only supports binding to Iterables such as Arrays. you can fix this problem like this <li *ngFor="let err of control.errors | keyvalue"> {{err.key}} </li> 🤔
  • This was my original aprouch. I wanted to change to get rid of the "complexity" (form.get(...)). Thats why I wanted something that looked similar to how you bind input controls.