2
votes

I am building dynamic objects using ReactiveFormsModule. My main module is app. Then I have a sub-module config. this component has ObjectConfigComponent and FieldConfigComponent.

I built using reference here The plunker mentioned in the article seems to work. I haven't been able to run mine.

Here is my code.

export class CompositeObject {
    public fields: Field[];
}

export class Field {
    public name: string;
    public datatype: DataType;
}

export enum DataType {
    string = 1,
    number,
    date
}

ObjectConfigComponent:

import { Component, OnInit } from '@angular/core';
import { CompositeObject } from './../../models/compositeobject';
import { Validators, FormGroup, FormArray, FormBuilder } from '@angular/forms';

@Component({
    selector: 'objectconfig',
    templateUrl: 'objectconfig.component.html'
})
export class ObjectConfigComponent implements OnInit {
    public myForm: FormGroup;
    constructor(private _formbuilder: FormBuilder) { }

    public ngOnInit() {
        this.myForm = this._formbuilder.group({
            fields: this._formbuilder.array([
                this.initField(),
            ])
        });
     }

    public save(model: CompositeObject ) {
         console.log(model);
    }

    private initField() {
        // initialize our address
        return this._formbuilder.group({
            name: ['', Validators.required],
            datatype: ['string', Validators.required]
        });
    }

    private addField() {
    // add address to the list
        const control = <FormArray>this.myForm.controls['fields'];
        control.push(this.initField());
    }

    private removeField(i: number) {
    // remove address from the list
        const control = <FormArray>this.myForm.controls['fields'];
        control.removeAt(i);
    }
}

HTML:

<div class="row">
    <div class="well bs-component">
        <form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm)">
            <!--fields-->
            <div formArrayName="fields">
                <div *ngFor="let field of myForm.controls.fields.controls; let i=index">
                    <div [formGroupName]="i">
                        <fieldform [group]="myForm.controls.fields.controls[i]"></fieldform>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="col-lg-10 col-lg-offset-2">
                    <button class="btn btn-link" (click)="addField()">Add another attribute</button>
                </div>
            </div>
            <div class="form-group">
                <div class="col-lg-10 col-lg-offset-2">
                    <button type="reset" class="btn btn-default">Cancel</button>
                    <button type="submit" class="btn btn-primary">Submit</button>
                </div>
            </div>
        </form>
    </div>
</div>

FieldFormComponent

import { Component, OnInit, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
    selector: 'fieldform',
    templateUrl: 'fieldform.component.html'
})
export class FieldFormComponent implements OnInit {
    @Input('group')
    public fieldForm: FormGroup;
    constructor() { }

    ngOnInit() { }
}

HTML

<div [formGroup]="fieldForm">
     <!-- Angular assigns array index as group name by default 0, 1, 2, ... -->
    <div class="form-group">
        <!--name-->
        <label class="col-lg-2 control-label">Attribute</label>
        <div class="col-lg-4">
            <input class="form-control"  id="inputName-{{i}}" type="text" formControlName="name">
            <!--display error message if street is not valid-->
            <small [hidden]="fieldForm.controls.name.valid">
                name is required
            </small>
        </div>
        <!--datatype-->
        <div class="col-lg-4">
            <select class="form-control" formControlName="datatype">
                <option>string</option>
                <option>number</option>
                <option>date</option>
            </select>
        </div>
    </div>
</div>

I am getting the following error:

Error: Uncaught (in promise): Error: Template parse errors: Can't bind to 'ngForOf' since it isn't a known property of 'div'. ("

        <div formArrayName="fields">

            <div [ERROR ->]*ngFor="let field of myForm.controls.fields.controls; let i=index">

                <div [formGr"): ObjectConfigComponent@5:21 Property binding ngForOf not used by any directive on an embedded

template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("

        <div formArrayName="fields">

            [ERROR ->]<div *ngFor="let field of myForm.controls.fields.controls; let i=index">

                <div [f"): ObjectConfigComponent@5:16

What am I doing wrong.

1

1 Answers

4
votes

Add

imports: [CommonModule]

to the @NgModule(...) that contains your component. Don't forget to import the package as well:

import { CommonModule } from "@angular/common";