Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: ControlValueAccessor vs @Input - When to use what with forms?

Tags:

angular

ControlValueAccessors popped up to me over the last months and I'm a bit confused on why or when I should use them instead of using @Input with my reactive forms.

Here's a sample code for how I've worked with reactive forms so far:

@Component({
 selector: 'app-my-component',
 template: `<input [formControl]="form.get('specificControlName')"  />` 
 // or the alternative method of [formGroup]="form" and formControlName="specificControlName"
})
export class MyComponent {
 @Input() form: FormGroup; // passed in formGroup

 ngOnInit() {
  form.valueChanges.pipe(
   // do rxjs magic here
  ).subscribe(value => {
   // do something with the value
  })
 }
}

Reactive Forms save the state of the form, so I can access that state even from the parent components. I can also access all the different NgControl attributes like valid, disabled, dirty, and touched.

What do ControlValueAccessors provide that this way of working with reactive forms don't? And what are some use cases where ControlValueAccessors work better than @Input and @Output in general?

EDIT:

https://medium.com/angular-in-depth/angular-nested-reactive-forms-using-cvas-b394ba2e5d0d

In this article the author mentions the following as the main differences:

Three Ways to implement nested forms:

...

  1. By passing a handle of the FormGroup to child components via Input and referencing it in child templates. There are couple of good tutorials on it.

But the con of using this approach is that you are tightly binding the parent form group with that of child group.

  1. Using Composite CVAs.

Pros: Highly Reusable, Portable. Better Encapsulation(Internal Form Controls of the component doesn’t necessarily need to be visible to parent components). This is best used when you have more number of form modules which is typically a large project.

Cons: Need to implement CVA interface results in boilerplate code.

This is interesting, but it raises a couple of more questions: Why and when do you not want your internal Form Controls to be visible to the parent? What does portable mean?

Also:

import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor,NG_VALUE_ACCESSOR, NG_VALIDATORS, FormGroup,FormControl, Validator, Validators,AbstractControl, ValidationErrors } from "@angular/forms";

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

public addressForm: FormGroup = new FormGroup({
  addressLine: new FormControl("",[Validators.required]),
  areacode: new FormControl('', [Validators.required, Validators.maxLength(5)])
});
  constructor() { }
  ngOnInit() {
  }

  public onTouched: () => void = () => {};

  writeValue(val: any): void {
    val && this.addressForm.setValue(val, { emitEvent: false });
  }
  registerOnChange(fn: any): void {
    console.log("on change");
    this.addressForm.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    console.log("on blur");
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.addressForm.disable() : this.addressForm.enable();
  }
}

when you're passing in a FormGroup into a ControlValueAccessor Component the author is initializing a new FormGroup inside of the component with the same structure as the passed in object. Isn't it better then to just pass in the FormGroup itself then? Or what benefits does the encapsulation provide?

EDIT2: This is an interesting video on the subject:

https://www.youtube.com/watch?v=CD_t3m2WMM8

like image 535
amouda Avatar asked Nov 26 '19 11:11

amouda


People also ask

What is the use of control value accessor in Angular?

ControlValueAccessorlink. Defines an interface that acts as a bridge between the Angular forms API and a native element in the DOM.

Why do we use FormControl in Angular?

In Angular, form controls are classes that can hold both the data values and the validation information of any form element. Every form input you have in a reactive form should be bound by a form control. These are the basic units that make up reactive forms.

How many types of form are in Angular and what is the difference between them?

Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture user input events from the view, validate the user input, create a form model and data model to update, and provide a way to track changes.

What is Ng_value_accessor?

NG_VALUE_ACCESSOR provider specifies a class that implements ControlValueAccessor interface and is used by Angular to setup synchronization with formControl . It's usually the class of the component or directive that registers the provider.


1 Answers

Use Standard Reactive Form API whenever you are using native HTML elements (input, select, button, form, etc)

Use ControlValueAccessor for example when you have to work with custom HTML elements (i.e. mat-list, mat-table, ag-grid-table, etc), the reason is because it's an interface that acts as a bridge between Angular forms API and DOM elements. ControlValueAccessor example

like image 184
Pedro Bezanilla Avatar answered Dec 07 '22 10:12

Pedro Bezanilla