带有 *ngFor、双向绑定 [(ngModel)] 和表单验证的 angular2 动态表单

angular2 dynamic form with *ngFor, two-way-binding [(ngModel)] and form validation

问题陈述

我正在尝试创建一个动态表单,其中部分界面响应模型的更新:

我被困在哪里

我目前的问题是我不知道如何从模板中引用新控制组(存储在 ControlArray 中)。

到目前为止,我发现的所有动态表单解决方案都可以在没有支持模型和双向数据绑定的情况下工作。

代码

我为以下代码创建了一个 plunkr:https://plnkr.co/edit/nP6hcIXKA0jz2F8Epg2L?p=preview

我的(简化的)数据模型:

class Entry {
    constructor(
        public _id: string,
        public _title: string
    ) {}
}

class Data {
    constructor(
        public heading: string,
        public entries: Entry[] = []
    ) {}
}

我的模板:

@Component({
    selector: 'my-app',
    template: `
        <h1>Dynamic Form</h1>
        <form [ngFormModel]="formModel">
            <label>heading: </label>
            <input type="text" [(ngModel)]="heading" [ngFormControl]="formModel.controls.heading">
            <div>
                <hr>
                <!-- PROBLEM: how to get a reference to a single Control from within ControlGroup from within formModel.controls['entries'] that can be wired with belows <input> fields? -->
                <div *ngFor="#entry of data.entries; #i = index">
                    <label>id: </label>
                    <input type="text" [(ngModel)]="entry._id" #ctrlId="ngForm"> <span><b>is valid: </b>{{ctrlId.control.valid}}</span>
                    <br>
                    <label>title: </label>
                    <input type="text" [(ngModel)]="entry._title" #ctrlTitle="ngForm"><span><b>is valid: </b>{{ctrlTitle.control.valid}}</span>
                    <hr>
                </div>
            </div>
        </form>
        <input type="button" (click)="add()" value="add new entry">
        <div>{{ctrlCount}}</div>
        <div>{{debug}}</div>
        <div>{{debugForm}}</div>
    `
}) 

我的组件:

export class DynamicForm implements OnInit {
    data:Data;

    formModel:ControlGroup;

    constructor(private fb:FormBuilder) {
        this.formModel = fb.group({
            heading: fb.control('test heading', Validators.required),
            entries: fb.array([])
        })
    }

    ngOnInit():void {
        /* init the heading */
        this.data = new Data('test heading');

        /* init the entries > add to model, create control and add it to ControlArray */
        [
            new Entry('1', 'one'),
            new Entry('2', 'two'),
            new Entry('3', 'three'),
            new Entry('4', 'four'),
        ].forEach((e:Entry) => this.add(e));
    }

    add(e:Entry):void {
        let id:string = e ? e._id : '';
        let title:string = e ? e._title : '';

        (<ControlArray>this.formModel.controls['entries']).push(this.fb.group({
            id: this.fb.control(id, Validators.required),
            title: this.fb.control(title, Validators.required),
        }));
        this.data.entries.push(new Entry(id, title));
    }

    get debug() {
        return JSON.stringify({debug_data: this.data});
    }

    get debugForm() {
        return JSON.stringify({
            debug_form: {
                dirty: this.formModel.dirty,
                pristine: this.formModel.pristine,
                touched: this.formModel.touched,
                untouched: this.formModel.untouched,
                valid: this.formModel.valid,
            }
        });
    }

    get ctrlCount() {
        return (<ControlArray>this.formModel.controls['entries']).length;
    }
}

ControlArray.at() 的描述:https://angular.io/docs/ts/latest/api/common/index/ControlArray-class.html#!#at-anchor