Reputation:
I have a couple of fields connected to the FormBuilder like this.
constructor(private builder: FormBuilder) {
this.form = builder.group({
"firstName": [...],
"lastName": [...]
});
}
In the markup, besides the fix controls, I'll also have an unknown number of input boxes. It's starting with zero and can be increased, as the user clicks on a button, which adds a new input box by each click. There'll be also a removal button for each input box so the number of those is fully dynamic.
<div class="input-caption">FirstName</div>
<input type="text" formControlName="firstName">
<div class="input-caption">LastName</div>
<input type="text" formControlName="lastName">
<div id="options"></div>
<button (click)="addOption()">Add option</button>
As the dynamically added fields need to be validated, I feel that I need to declare them in the group definition. I have no idea how, though.
When I googled, I got a bunch of hits on [(ngModel)]
but I also read that it's supposed to be used with the FormsModule
and not ReactiveFormsModule
as discussed in a blog.
How should I approach it? Is double-bound ngModel the only option?
Edit based on the answer.
HTML
<div *ngFor="let tag of []; let i = index;" [formGroupName]="i">
<div class="input-caption">Tag</div>
<input formControlName="name"> -->
</div>
TS
constructor(private builder: FormBuilder) {
this.form = builder.group({
"firstName": [...],
"lastName": [...],
"tags": this.builder.array([]),
});
}
addTag(): void {
(this.form.controls.tags as FormArray).???;
}
I've also tried to specify a hard-coded array in the markup as follows but didn't get to see any controls being rendered.
<div *ngFor="let tag of [{'name':'uno'},{'name':'duo'}]; let i = index;"
[formGroupName]="i">
<div class="input-caption">Tag</div>
<input formControlName="name"> -->
</div>
Upvotes: 1
Views: 333
Reputation: 60518
If you just want this code to work, you just need to change it to an array:
<div *ngFor="let tag of ['uno','duo']; let i = index;"
[formGroupName]="i">
<div class="input-caption">{{ tag }}</div>
<input formControlName="name"> -->
</div>
And they don't really need to be form groups. It would probably be simpler if they aren't:
<div *ngFor="let tag of ['uno','duo']">
<div class="input-caption">{{ tag }}</div>
<input [formControlName]="tag"> -->
</div>
And if this is all you need ... then you don't really even need FormArrays.
Upvotes: 0
Reputation: 60518
Your scenario is the purpose of a FormArray. See the docs here: https://angular.io/guide/reactive-forms#use-formarray-to-present-an-array-of-formgroups
The docs show an array of FormGroups, but you can also use it to create an array of FormControls.
Here is an example from my application:
this.productForm = this.fb.group({
productName: ['', [Validators.required,
Validators.minLength(3),
Validators.maxLength(50)]],
productCode: ['', Validators.required],
starRating: ['', NumberValidators.range(1, 5)],
tags: this.fb.array([]),
description: ''
});
My "tags" look like this:
I set default values into these controls like this:
// Update the data on the form
this.productForm.patchValue({
productName: this.product.productName,
productCode: this.product.productCode,
starRating: this.product.starRating,
description: this.product.description
});
this.productForm.setControl('tags', this.fb.array(this.product.tags || []));
You can find my sample code here: https://github.com/DeborahK/Angular2-ReactiveForms In the "APM" or "APM - Updated" folders.
This is the code from the Pluralsight course: Angular Reactive Forms
here: https://app.pluralsight.com/library/courses/angular-2-reactive-forms/table-of-contents
Upvotes: 2