4

I am trying to add rows to a form. Each row has 3 input fields.

This is what I've done so far.

export class MedicationGrid {
   title1:string;
   title2:string;
   title3:string;
}

component html

  <li class="am-row" *ngFor="let dynamic of dynamicArray; let i = index;">
    <div class="medication-name">
    <input  type="text" class="form-control am-medicine" placeholder="Medicine" [(ngModel)]="dynamicArray[i].title1"  name="medicine" required />
    </div>
   <div class="medication-dosage">
   <input type="text" class="form-control am-dosage" placeholder="Dosage"       [(ngModel)]="dynamicArray[i].title2" name="dosage" />
   </div>
   <div class="medication-frequency">
   <input type="text" class="form-control am-frequency" placeholder="Frequency" [(ngModel)]="dynamicArray[i].title3" name="frequency" />
  </div>
  <div class="medication-add">
   <img src="../../../assets/img/actionModal/add.png" (click)="addMedicationRow(i)"  />
  </div>
 </li>

component.ts

ngOnInit() {
    this.newDynamic = {title1:"", title2:"", title3:""};
    this.dynamicArray.push(this.newDynamic);
}

addMedicationRow(index) {
   this.newDynamic = {title1:"", title2:"", title3:""};
   this.dynamicArray.push(this.newDynamic);
   return true;
 }

I can add new rows with this. But the problem is, when i enter some data in to the fields and click the add button, all the data is gone along with the new row is inserted. How do I fix this?

2

2 Answers 2

4

You can use FormGroup and FormControl to create controls. Let me show an example:

It can be seen at stackblitz example.

HTML:

<form [formGroup]="myForm">
    <ng-container *ngFor="let group of myForm.controls |keyvalue">
        <div style="margin:20px;" [formGroup]="group.value">
            <label for="">{{group.key}} test</label>
            <input type="text" formControlName="name">
            <button type="button" (click)="onAddMedicine(group.value)">Add Medicine</button>
            <div formArrayName="medicineList">
                <div *ngFor="let item of medicineArray(group.value).controls; let i = index">
                    <label for="">Medicine row</label>
                    <input [formControlName]="i">
          <button (click)="removeMedicine(group.value,i)">remove</button>
      </div>
                </div>
            </div>
    </ng-container>
</form>
<pre>
{{myForm?.value|json}}
</pre>

TypeScript:

public myForm: FormGroup;

ngOnInit() {
    this.myForm = new FormGroup({});
    for(let item of ['item1']) {
        this.myForm.addControl(item,
            new FormGroup({
                name: new FormControl(),
                medicineList: new FormArray([])
            })
        )
    } 
} 

onAddMedicine(group:FormGroup) {
    (group.get('medicineList') as FormArray).push(new FormControl())
}

medicineArray(group:FormGroup):FormArray
{
    return group.get('medicineList') as FormArray
}

removeMedicine(group:FormGroup,index:number)
{
    (group.get('medicineList') as FormArray).removeAt(index)
}
Sign up to request clarification or add additional context in comments.

Comments

3

This guide is completly copied from: https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/

"So you have a form and would like to add form fields dynamically from a response to a user event? It’s easy to do with Reactive Forms and FormArray. FormArray is a bit like FormGroup and it’s used in a very similar way, the difference being that it’s used as an array that wraps around an arbitrary amount of FormControl, FormGroup or even other FormArray instances."

Importing FormArray

First, on top of your other form imports, you’ll want to import FormArray from the Angular forms module:

import { FormBuilder, FormGroup, FormArray } from '@angular/forms';

// ...

Initializing the Form

Now we’ll initialize our form using FormBuilder in the ngOnInit hook. For this example we’ll create an order form that allows the user to add new items dynamically:

orderForm: FormGroup;
items: FormArray;

constructor(private formBuilder: FormBuilder) {}

ngOnInit() {
  this.orderForm = this.formBuilder.group({
    customerName: '',
    email: '',
    items: this.formBuilder.array([ this.createItem() ])
  });
}

Our items instance is a form array instead of a form control, and we’re calling a createItem method to create a form group as the first item in our array. Here’s what our createItem method looks like:

createItem(): FormGroup {
  return this.formBuilder.group({
    name: '',
    description: '',
    price: ''
  });
}

Adding to the FormArray Dynamically

Now the interesting part is that we can to treat our FormArray just like a regular array and push new items into it:

addItem(): void {
  this.items = this.orderForm.get('items') as FormArray;
  this.items.push(this.createItem());
}

Now it’s as simple as calling our addItem method in our template when the user clicks to add a new item.

FormArray in the Template

Finally, we use the formArrayName directive in the template to bind to our form array:

<div formArrayName="items"
  *ngFor="let item of orderForm.get('items').controls; let i = index;">
  <div [formGroupName]="i">
    <input formControlName="name" placeholder="Item name">
    <input formControlName="description" placeholder="Item description">
    <input formControlName="price" placeholder="Item price">
  </div>

  Chosen name: {{ orderForm.controls.items.controls[i].controls.name.value }}
</div>

Notice how our formGroupName directives now take an index instead of a name and we set it using the index that ngFor gives us.

You can also see a way to get to a form control’s value in the template by traversing our form.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.