I am implementing atomic design in my Angular 9 application. This means that I will build my pages with atoms, molecules & organisms. All is going fine, except for the ReactiveFormsModule.
I want to convert the <input />
to its own component, so that I don't have to duplicate the associated HTML all the time. However, reactive forms is not having any of it.
The sample below is returns an error onload: ERROR Error: No value accessor for form control with name: 'field2'
I made a StackBlitz example with the full code.
app.component.ts
import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({selector: 'app-root',templateUrl: './app.component.html'})
export class AppComponent {
form: FormGroup;
constructor(fb: FormBuilder) {
this.form = fb.group({
field1: ['value1', [Validators.required]],
field2: ['value2', [Validators.required]],
});
}
onSubmit() {console.log(this.form.value);}
}
app.component.html Here I tried replacing the second input with the atom.
<form [formGroup]="form" (ngSubmit)="onSubmit();">
<label>
Field 1 <input formControlName="field1" />
</label>
<label>
Field 2 <app-input formControlName="field2"></app-input>
</label>
<button type="submit">Submit</button>
</form>
input.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-input',
template: '<input [formControlName]="formControlName" />',
})
export class InputComponent implements OnInit {
@Input() formControlName: string;
constructor() { }
ngOnInit(): void {
}
}
I have tried to implement a ControlValueAccessor
, through this tutorial but this resulted in weird behaviour.
Can anyone show me how to achieve this?
if u want to make ur life easy then use FormControl as input from ur custom component this is code from my app
// custom component
@Input() set control(value: FormControl) {
if (this._control !== value) {
this._control = value;
}
}
// tempalte
<input [formControl]="_control">
input parent control i not using formBuilder but fromControl and formGroup directly.
name = new FormControl('');
constructor(){
let name = this.name;
this.formGroup = new FromGroup({name });
// template
<custom-control [control]="name">
app.component.ts
import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({selector: 'app-root',templateUrl: './app.component.html'})
export class AppComponent {
form: FormGroup;
constructor(fb: FormBuilder) {
this.form = fb.group({
field1: ['value1', [Validators.required]],
field2: ['value2', [Validators.required]],
});
}
onSubmit() {console.log(this.form.value);}
}
app.component.html
<form [formGroup]="form" (ngSubmit)="onSubmit();">
<label>
Field 1 <input formControlName="field1" />
</label>
<label>
Field 2 <app-input [control]="form.controls.field2"></app-input>
</label>
<button type="submit">Submit</button>
</form>
input.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-input',
template: '<input [formControl]="formControl" />',
})
export class InputComponent implements OnInit {
@Input() set control(value: FormControl) {
if (this.formControl !== value) {
this.formControl = value;
}
}
formControl: FormControl;
constructor() { }
ngOnInit(): void { }
}