An array of users can have multiple elements (users). In a template, I iterate over this array and add a form for each element. Right now each form binds to the same form group values. If I fill out the form for the first user, submit buttons of all the forms become enabled. How to point each form to the unique formGroup or unique variables?
component:
import { FormControl, FormGroup, Validators, FormBuilder} from '@angular/forms';
...
export class UserComponent implements OnInit {
form: FormGroup;
@input users: any[];
constructor(private _fb: FormBuilder) {}
ngOnInit() {
this.form = this._fb.group({
address: new FormControl('', [Validators.required]),
phone: new FormControl('', [Validators.required]),
});
}
add() {
if (this.form.valid){
// code
}
}
Template:
<div *ngFor="let user if users">
{{user.name}}
<form [formGroup]="form" (ngSubmit)="add()">
<div class="form-group">
<label>Address:</label>
<input formControlName="address" class="form-control">
<label>Phone:</label>
<input formControlName="phone" class="form-control"></input>
</div>
<button type="submit" class="submit" [disabled]="!form.valid">Submit</button>
</form>
</div>
To solve your problem you have to use formArray
as follows:
In the component:
export class UserComponent implements OnInit {
usersForm: FormGroup;
errorMessage : string;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.usersForm= this.formBuilder.group({
users: this.formBuilder.array([
this.formBuilder.group({
address: [null, [Validators.required]],
phone: [null, [Validators.required]]
})
])
});
}
initUserRow(): FormGroup {
return this.formBuilder.group({
address: [null, [Validators.required]],
phone: [null, [Validators.required]],
});
}
addUserRow(): void {
const usersArray=
<FormArray>this.usersForm.controls['users'];
usersArray.push(this.initUserRow());
}
removeUserRow(rowIndex: number): void {
const usersArray= <FormArray>this.usersForm.controls['users'];
if (usersArray.length > 1) {
usersArray.removeAt(rowIndex);
} else {
this.errorMessage = 'You cannot delete this row! form should contain at least one row!';
setTimeout(() => {
this.errorMessage = null;
}, 4000);
}
}
}
In the view:
<form *ngIf="usersForm" [formGroup]="usersForm" (ngSubmit)="createUsers()">
<table class="table table-sm table-bordered">
<thead>
<tr class="text-center">
<th>Address</th>
<th>Phone</th>
<th>Action</th>
</tr>
</thead>
<tbody formArrayName="users">
<tr *ngFor="let item of usersForm.controls.users.controls; let $index=index" [formGroupName]="$index">
<td style="min-width: 120px">
<input class="form-control" type="text" formControlName="address"/>
<div class="text-danger" *ngIf="usersForm.controls['users'].controls[$index].controls['address'].touched
&& usersForm.controls['users'].controls[$index].controls['address'].hasError('required')">
Please enter address!
</div>
</td>
<td style="min-width: 120px">
<input class="form-control" type="text" formControlName="address"/>
<div class="text-danger" *ngIf="usersForm.controls['users'].controls[$index].controls['phone'].touched
&& usersForm.controls['users'].controls[$index].controls['phone'].hasError('required')">
Please enter phone number!
</div>
</td>
<td style="width: 100px">
<button (click)="addUserRow()" class="btn btn-success btn-sm mr-1" type="button"><i class="fa fa-plus"></i></button>
<button (click)="removeUserRow($index)" class="btn btn-danger btn-sm" type="button"><i class="fa fa-times"></i></button>
</td>
</tr>
</tbody>
</table>
</form>
Hope now your problem will be solved!
With reactive forms, you define the data structure to hold the form data in your code. In your example, you define it with this.form
. But your form definition only has one address control and one phone control. So you've told Angular to only store one address and one phone.
To allow for multiple address/phone sets, you need a FormArray as mentioned by @DavidZ. As its name implies, a FormArray allows you to have an array of form values.
In your example, your FormArray would be comprised of a FormGroup with one entry for each user. The FormGroup would be comprised of the set of FormControls: the address and the phone.
Form Component
This example has a name and an array of addresses, but should give you a general idea:
ngOnInit(): void {
this.customerForm = this.fb.group({
name: ['', [Validators.required, Validators.minLength(3)]],
addresses: this.fb.array([this.buildAddress()])
});
}
buildAddress(): FormGroup {
return this.fb.group({
addressType: 'home',
street1: ['', Validators.required],
street2: '',
city: '',
state: '',
zip: ''
});
}
You can find the complete code for this here: https://github.com/DeborahK/Angular2-ReactiveForms/tree/master/Demo-Final-Updated
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With