0

I do have a custom component for template driven form where I use NG_VALUE_ACCESSOR. It works really good. Now I would like to switch to reactive form. StackBlitz Demo

The issue is that how to use a reactive form as a custom component and pass formGroup and formControlName and also how to pass the rest of the other attributes dynamically to the parent component such as required etc.

The required attribute as fare as I know, is being defined in the *.component.ts file. Therefore it would not be possible to set dynamically in the parent as an attribute binding like in template driven form.

I have been searching but unfortunately no significant result.

Any Idea how could I implement reactive form as custom component using NG_VALUE_ACCESSOR and passing attribute dynamically?

1 Answer 1

2

Really I don't know what do you want. Your custom form control work with reactive Forms too (see your custom form control using reactive form)

<form [formGroup]="myForm">
   <app-elements-input formControlName="name" ...>
   </app-elements-input>
</form>
//and 
myForm=new FormGroup(
    {
        name:new FormControl()
    }
  )

Well some times it's necesary know when the control is invalid, touched...

A easy way is add as provider NG_VALIDATORS

{provide: NG_VALIDATORS,
      useExisting:forwardRef(() => InputComponent), 
       multi: true} 

Add one variable, e.g.

control:any=null;

e implements Validator, that's add in the declaration and create a function validate where we give value to "control"

export class InputComponent implements ...,Validator {..}

public validate(c: FormControl) {
  if (!this.control)
    this.control=c;
  return null;
 // return (!this._value && !this.required)?{required:true}:null
}

So you can use in html some like

<span *ngIf="control?.invalid">*</span>

Don't forget indicate when the control is touched, in the example, we can use the event (blur) of the input

<input ... (blur)="onTouched()">

If you want make a component to control a formgroup it's only pass as `@Input()' the fromGroup or the formControl

<form [formGroup]="myForm">
       <children [argformControl]="myForm.get('name')">
       </children>
</form>
//and
@Input() argformControl:FormControl

or

<form [formGroup]="myForm">
       <children [argFormGroup]="myForm">
       </children>
</form>
//and
@Input() argFormGroup:FormGroup

Update this allow as, e.g. if we has an array of object like

data=[{name:'name',label:'Name'},{name:'surname',label:'Surname'}]

make some like

<!--I add a "clasic" *ngIf to avoid initialize problems
   It can be placed in the form, or in children-->
<form *ngIf="myForm" [formGroup]="myForm">
   <children [argFormGroup]="myForm" [data]="data">
   </children>
</form>

And our children becomes

<div *ngFor="let item of data">
{{item.label}}<input [formControl]="argFormGroup.get(item.name)">
</div>
//and 
 @Input() argFormGroup:FormGroup
 @Input() data:any[]

A custom formControl is a "black box". You send a value -a string, a object...- and you can modify this string or object. It's look like a "complex input" (a mat-date-picker, e.g. is a custom form control)

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks. But I think I missed to mention the case where I would use more than one input text in the parent component. So, let's say I do have two text fields with two different names. How would 2 different names attributes works? The idea behind this concept is to be able to embed much input fields as want and pass them different names. And I don't need to make any changes in the *.component.ts file. I think the formControlName="name" should be dynamic.
I updated my answer. The key is use [formControl], not [formControlName]
Unfortunately still not working. When I add the input twice with 2 different names e.g. <app-elements-input [type]="'text'" formControl="name"....></app-elements-input><br><app-elements-input [type]="'text'" formControl="name2"....></app-elements-input>. the console throws: ERROR TypeError: Cannot create property 'validator' on string 'name' and ERROR TypeError: Cannot create property 'validator' on string 'name2'. I have been testing it on your StackBlitz Demo.
@k.vincent, You're rigth, we need put a *ngIf to avoid initialize problems -exists "data", but not exist myForm2. So, <form *ngIf="myForm2" [formGroup]="myForm2">. I've just updated the stackblitz. -another way is in children use <ng-container *ngIf="argFormGroup">....</ng-container>
Thanks again. Still not there. I want to make this part name:new FormControl('',Validators.required), surname:new FormControl('',Validators.required) dynamic. I don't want to touch the app.component.ts to add an extra formControlName and also the required attribute should be defined in the View if I need to make the filed mandatory like<children [argFormGroup]="myForm2" [data]="data" required="true"> </children> not in the TS file.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.