How to add more input fields using a button - Angular 2 dynamic forms
Asked Answered
P

3

8

So I used the guide here: https://angular.io/docs/ts/latest/cookbook/dynamic-form.html

I need to add more fields to an existing field. I've made something that works, but it's clunky and it resets the form when I hit it. Code below:

In dynamic-form.component.ts:

add_textbox()
{
    this.questions.push(this.questionService.create_textbox({key: "test", label: "Test"}));
    console.log(this.questions);
    this.form = this.qcs.toFormGroup(this.questions);
}

In question.service.ts

create_textbox({key, value, label = '', order = 1, type = "text", description = "", help = ""}: {key?: any, value?: any, label?: any, order?: any, type?: any, description?: any, help?: any})
{
    return new TextboxQuestion({
        key,
        label,
        value,
        order,
        description,
        type
    });
}

My button is also in dynamic-form.component.html but I'd like it to be in dynamic-form-question.component.ts instead. Is this possible?

Polybius answered 21/12, 2016 at 6:56 Comment(0)
W
19

first of all

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

then

 addForm: FormGroup; // form group instance

constructor(private formBuilder: FormBuilder) {}
    ngOnInit() { 
        //    *** this is code for adding invoice details ***
         this.addForm = this.formBuilder.group({
            invoice_no: ['', Validators.required],
            file_no: ['', Validators.required],
            description: ['', Validators.required],
            linktodrive: this.formBuilder.array([
                this.initLink(),
            ])
        });
    }
    initLink() {
        return this.formBuilder.group({
            linkAddress: ['', Validators.required]
        });
    }
    addLink() {
        const control = < FormArray > this.addForm.controls['linktodrive'];
        control.push(this.initLink());
    }
    removeLink(i: number) {
        const control = < FormArray > this.addForm.controls['linktodrive'];
        control.removeAt(i);
    }

Begin and close your HTML with:

<div formArrayName="linktodrive"></div>

For creating and removing dynamic fields to your form use this html:

<div *ngFor="let address of addForm.controls.linktodrive.controls; let i=index">
<div>
<span>Link {{i + 1}}</span>
<span *ngIf="addForm.controls.linktodrive.controls.length > 1"><a (click)="removeLink(i)">REMOVE</a></span>
</div>

<!-- Angular assigns array index as group name by default 0, 1, 2, ... -->
<div [formGroupName]="i">
<input type="text" placeholder="Enter Link" formControlName="linkAddress">
</div>
</div>

And finally the "ADD" link

<div><a (click)="addLink()"></a></div>
Whitcher answered 21/12, 2016 at 7:31 Comment(6)
@Stephen Kuehl I have used same code in my project. It works for me. If you are getting some error then you then may be doing something wrong. It's working boss that's why it have upvote. Share your errorWhitcher
Error: Cannot find control with path: '0 -> linkAddress'. This error point to my html file on the line where <div [formGroupName]="i" startsTimmons
for complete detail check this link scotch.io/tutorials/… . it will help you to understand :)Whitcher
You forgot to mention that you need to wrap the HTML in <div formArrayName="addresses">Timmons
@StephenKuehl if you find something is missing then you can edit my answer. i will accept the changes. it may help other programmers also.Whitcher
It gives array of objects . But i need it as values inside an object ..is it possible?Undermanned
G
2

i went through a very useful blog post and that worked fine. dynamically add rows in reactive forms angular 6. Comment for any sort of doubts in the code

Gwenny answered 26/4, 2019 at 12:34 Comment(0)
U
1

The winning solution might be a bit outdated. Code to works with new ng'6 syntax would look more or less like this:

controller:

form = this.fb.group({
    title: ['New Project Name'],
    tasks: this.fb.group({
        title: ['Task title XX'],
        content: ['What is this about'],
        **subtasks: this.fb.array([this.initTask()]),**
        points: ['5'],
        hints: ['No hints']
    })
});
constructor(private fb: FormBuilder) {}

ngOnInit() {}

onSubmit() {
    console.log(this.form);
}

initTask() {
    return this.fb.group({
        subtask: ['', Validators.required]
    });
}

get tasksControl () {
    return this.form.get('tasks') as FormGroup;
}

get subtaskControl () {
    return this.tasksControl.get('subtasks') as FormArray;
}

addLink() {
    this.subtaskControl.push(this.initTask());
}
removeLink(i: number) {
    this.subtaskControl.removeAt(i);
}

and with html like this:

<div formArrayName="subtasks">
    <div *ngFor="let subtask of subtaskControl.controls; let i=index">
        <div [formGroupName]="i">
            <input type="text" placeholder="Enter Link" formControlName="subtask">
        </div>
        <div>
            <a class="btn btn-danger btn-sm" (click)="removeLink(i)">REMOVE</a>
            <a class="btn btn-success btn-sm" (click)="addLink()">Add</a>
        </div>
    </div>
</div>
Ursuline answered 16/9, 2018 at 21:47 Comment(1)
Here i get this error - ERROR TypeError: Cannot read property 'getFormGroup' of null at FormGroupName.get [as control] (forms.js:1849)Howardhowarth

© 2022 - 2024 — McMap. All rights reserved.