As always, a FormArray can be a FormArray of FormControls or a FormArray of FormGroups. A FormArray of FormControls are to store an array of "string" (or array of "number") a FormArray of FormGroup is to store an array of objects)
You only want to store an array, so you need a FormArray of Controls
form=new FormGroup({
remarks:new FormArray([new FormControl(null,Validators.required)])
})
As always we manage a FormArray we use a "getter" of the FormArray
get remarks()
{
return this.form.get('remarks') as FormArray
}
And typical functions to add and remove an element of the FormArray
addRemark(data:string=null)
{
this.remarks.push(new FormControl(data,Validators.required))
}
removeRemark(index:number)
{
this.remarks.removeAt(index)
}
The .html. See that we use in the input [formControlName]="i" and there're no formGroupName
<form [formGroup]="form">
<button (click)="addRemark()">add</button>
<div formArrayName="remarks">
<div *ngFor="let control of remarks.controls; let i = index">
<textarea [formControlName]="i"></textarea>
<button (click)="removeRemark(i)">remove</button>
</div>
</div>
</form>
Well, this is a typical formArray inside a FormGroup. Really if we only want a FormArray, we needn't use a FormGroup. We can define directly
remarks=new FormArray([new FormControl(null,Validators.required)]);
The problem, now is that we can not use [formControlName]="i"when we iterate. We can think in write some like [formControl]="remarks.at(i)" but Angular say us that "Type 'AbstractControl' is missing the following properties from type 'FormControl'". That's mean that Angular doesn't know that is really FormControl. So we need a function that returns our FormControl
getControl(index:number)
{
return this.remarks.at(i) as FormControl
}
And know we can use [formControl]
<button (click)="addRemark()">add</button>
<div *ngFor="let control of remarks.controls; let i = index">
<textarea [formControl]="getControl(i)"></textarea
>
<button (click)="removeRemark(i)">remove</button>
</div>
In this stackblitz you have the two approaches using a FormArray
Well, about adding elements dynamically or not. You can have an array with data, e.g.
data=["one","two","three"...]
When you create the formArray you can use "map"
remarks=new FormArray(this.data.map(x=>new FormControl(x,Validators.required))
Looks complex but see that the only we make is transform the array "this.data" (an array of strings) into an array of FormControls. (is the function of map). Then we use the array to create the FormArray. If we can make more "step by step"
const arrayOfFormControls=this.data.map(x=>new
FormControl(x,Validators.required)
remarks=new FormArray(arrayOfFormControls)
or even more "step" instead use map use a forEach
const arrayOfFormControls=[] //<--a empty array
this.data.forEach(x=>
{
arrayOfFormControls.push(new FormControl(x,Validators.required)
})
remarks=new FormArray(arrayOfFormControls)