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?

Mistalis
  • 16,351
  • 13
  • 68
  • 91
A. L
  • 9,009
  • 15
  • 53
  • 121

3 Answers3

18

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>
Stephen Kuehl
  • 95
  • 1
  • 13
Amit kumar
  • 5,341
  • 5
  • 23
  • 38
  • @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 error – Amit kumar May 31 '17 at 14:57
  • 1
    Error: Cannot find control with path: '0 -> linkAddress'. This error point to my html file on the line where
    – Stephen Kuehl May 31 '17 at 15:14
  • for complete detail check this link https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2 . it will help you to understand :) – Amit kumar May 31 '17 at 16:03
  • 1
    You forgot to mention that you need to wrap the HTML in `
    `
    – Stephen Kuehl May 31 '17 at 16:13
  • @StephenKuehl if you find something is missing then you can edit my answer. i will accept the changes. it may help other programmers also. – Amit kumar May 31 '17 at 16:16
  • It gives array of objects . But i need it as values inside an object ..is it possible? – Mr. Sha Jun 15 '17 at 05:13
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

Akshay Antony
  • 423
  • 2
  • 10
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>
  • 1
    Here i get this error - ERROR TypeError: Cannot read property 'getFormGroup' of null at FormGroupName.get [as control] (forms.js:1849) – Techdive Oct 29 '18 at 13:48