Angular FormArray绑定错误:找不到路径为“ addressess-> 0-> street”的控件

时间:2019-02-21 12:10:14

标签: angular angular-reactive-forms

我正在开发一个反应性的表格,例如在控制台中出现错误

请找到我尝试复制的stackblitz链接

https://stackblitz.com/edit/angular-nqnfkn

Cannot find control with path: 'addressess -> 0 -> street'
Cannot find control with path: 'addressess -> 0 -> line2'
Cannot find control with path: 'addressess -> 0 -> line3'

我在窗体上的控件很少,它们是窗体数组。我的困惑是在setFormValues方法的patchValue中设置这些值。到目前为止,我一直通过这种方式对索引进行硬编码来绑定数据

  const websiteGroup = this._fb.group({
            websiteUrl: FirmDetails.Websites[0].WEBSITE_URL,
            username: FirmDetails.Websites[0].USERNAME,
            password: FirmDetails.Websites[0].PASSWORD
            // websites: FirmDetails.Websites
        });

我现在尝试将其更改为

 const websiteGroup = this._fb.group({
       // websiteUrl: FirmDetails.Websites[0].WEBSITE_URL,
        //username: FirmDetails.Websites[0].USERNAME,
        //password: FirmDetails.Websites[0].PASSWORD
          websites: FirmDetails.Websites
    });

但是这样做,我遇到了以上错误

UI

<style>
    .desc-header {
        background-color: #FAE7D6;
        color: black
    }

    .header {
        width: 8%;
    }


    .panel-heading {
        color: white;
        background-color: #F59850;
        border-color: #ddd;
    }

    .scrollClass {
        height: 800px;
        overflow-y: scroll;
        overflow-x: hidden;


    }
</style>

<div class="card">
    <div class="card-header panel-heading">
        <span style="font-size: 18px; font-weight: bold; ">Firm Details</span>
        <div class="pull-right" style="padding-right:10px;">
            <label class="btn btn-primary" [ngClass]="{'btn-primary': EditMode, 'btn-default': !EditMode }"><input
                    type="checkbox" [(ngModel)]="EditMode" class="hidden">Edit Mode</label>

        </div>
    </div>
    <div class="card-body">

        <form [formGroup]="frmFirm" (ngSubmit)="onSubmit()">
            <div *ngIf="FirmDetails && FirmDetails.Firm" class="card-body scrollClass" style="width:100%">

                <div class="form-group row">
                    <label for="inputName" class="col-md-1 col-form-label modal-label header">Name</label>
                    <div class="col-md-3">
                        <div *ngIf="!EditMode">{{FirmDetails.Firm.NAME}}</div>
                        <input *ngIf="EditMode" kendoTextBox [readonly]="false" class="form-control"
                            formControlName="firmName" />
                    </div>


                </div>

                <div class="form-group row">
                    <label for="inputTitle" class="col-md-1 col-form-label header">Short Name</label>
                    <div class="col-md-3">
                        <div *ngIf="!EditMode">{{FirmDetails.Firm.SHORT_NAME}}</div>
                        <input *ngIf="EditMode" kendoTextBox [readonly]="false" class="form-control"
                            formControlName="shortName" />
                    </div>
                </div>

                <div class="form-group row">
                    <label for="inputEmail" class="col-md-1 col-form-label header">Alternate Name</label>
                    <div class="col-md-3">
                        <div *ngIf="!EditMode">{{FirmDetails.Firm.ALTERNATE_NAME}}</div>
                        <input *ngIf="EditMode" kendoTextBox [readonly]="false" class="form-control"
                            formControlName="alternateName" />
                    </div>
                </div>

                <div class="form-group row">
                    <label for="inputEmail" class="col-md-1 col-form-label header">Date Founded</label>
                    <div class="col-md-3">
                        <div *ngIf="!EditMode">{{dateFoundedDate}}</div>
                        <kendo-datepicker *ngIf="EditMode" [format]="'MMMM yyyy'" formControlName="dateFounded">
                        </kendo-datepicker>
                    </div>
                </div>


                <div class="form-group row">
                    <label for="inputEmail" class="col-md-1 col-form-label header">Intralinks Connections</label>
                    <div class="col-md-9">
                        <div class="form-group row">
                            <div class="col-md-3">
                                <label for="inputEmail">User Name</label>
                            </div>
                            <div class="col-md-3">
                                <label for="inputEmail">Password</label>
                            </div>
                        </div>


                        <div formArrayName="intraLinks"
                            *ngFor="let item of frmFirm.get('intraLinks').controls; let i = index; let last = last">
                            <div [formGroupName]="i">
                                <div class="form-group row">
                                    <div class="col-md-3">
                                        <input style="width:100%" formControlName="intraUsername"
                                            placeholder="User Name">
                                    </div>
                                    <div class="col-md-3">
                                        <input style="width:100%" formControlName="intraPassword"
                                            placeholder="Password">
                                    </div>
                                    <div *ngIf="EditMode" class="col-md-3">
                                        <button class="fa fa-trash" (click)="removeCredentials()"></button>
                                    </div>
                                </div>


                            </div>

                        </div>
                        <div *ngIf="EditMode">
                            <button (click)="addCredentials()">Add Credentials</button>
                        </div>
                    </div>
                </div>


                <div class="form-group row">
                    <label for="inputEmail" class="col-md-1 col-form-label header">Key Contact</label>
                    <div class="col-md-3">
                        <div *ngIf="!EditMode && FirmDetails.People">{{FirmDetails.KeyContact.Name}}</div>
                        <kendo-dropdownlist *ngIf="EditMode" style="width:100%" [data]="FirmDetails.People"
                            formControlName="People" [defaultItem]="FirmDetails.KeyContact.Name" [valuePrimitive]="true"
                            [filterable]="false" textField="Name" valueField="ID"></kendo-dropdownlist>
                    </div>
                </div>

                <div class="form-group row">
                    <label for="inputEmail" class="col-md-1 col-form-label header">Websites</label>
                    <div class="col-md-9">
                        <div class="form-group row">
                            <div class="col-md-3">
                                <label for="inputEmail">Website URL</label>
                            </div>
                            <div class="col-md-3">
                                <label for="inputEmail">User Name</label>
                            </div>
                            <div class="col-md-3">
                                <label for="inputEmail">Password</label>
                            </div>
                        </div>


                        <div formArrayName="websites"
                            *ngFor="let item of frmFirm.get('websites').controls; let i = index; let last = last">
                            <div [formGroupName]="i">
                                <div class="form-group row">
                                    <div class="col-md-3">
                                        <input style="width:100%" formControlName="websiteUrl"
                                            placeholder="Website Url">
                                    </div>
                                    <div class="col-md-3">
                                        <input style="width:100%" formControlName="username" placeholder="User Name">
                                    </div>
                                    <div class="col-md-3">
                                        <input style="width:100%" formControlName="password" placeholder="Password">
                                    </div>
                                    <div *ngIf="EditMode" class="col-md-3">
                                        <button (click)="removeWebsite()">Remove Website</button>
                                    </div>
                                </div>


                            </div>

                        </div>
                        <div *ngIf="EditMode">
                            <button (click)="addWebsite()">Add Website</button>
                        </div>
                    </div>
                </div>


                <div class="form-group row">
                    <!-- <label for="inputEmail" class="col-md-1 col-form-label header">Addresses</label> -->
                    <div class="col-md-9">
                        <!-- <div *ngIf="!EditMode">{{FirmDetails.Firm.Addresses}}</div> -->
                        <!-- <input *ngIf="EditMode" kendoTextBox [readonly]="false" class="form-control" /> -->

                        <div formArrayName="addressess"
                            *ngFor="let item of frmFirm.get('addressess').controls; let i = index;">

                            <div [formGroupName]="i">

                                <div class="form-group row">
                                    <label class="col-md-1 col-form-label header" attr.for="{{'streetId' + i}}">Street
                                        1</label>
                                    <div class="col-md-9">
                                        <input class="form-control" id="{{'streetId' + i}}" type="text"
                                            placeholder="Street address (required)" formControlName="street">

                                    </div>
                                </div>

                                <div class="form-group row">
                                    <label class="col-md-1 col-form-label header" attr.for="{{'line2Id' + i}}">Line
                                        2</label>
                                    <div class="col-md-9">
                                        <input class="form-control" id="{{'line2Id' + i}}" type="text"
                                            placeholder="Street address (second line)" formControlName="line2">
                                    </div>
                                </div>

                                <div class="form-group row">
                                    <label class="col-md-1 col-form-label header" attr.for="{{'line3Id' + i}}">Line
                                        3</label>
                                    <div class="col-md-9">
                                        <input class="form-control" id="{{'line3Id' + i}}" type="text"
                                            placeholder="Street address (third line)" formControlName="line3">
                                    </div>
                                </div>

                                <div class="form-group row ">
                                    <label class="col-md-1 col-form-label header" attr.for="{{'cityId' + i}}">City, Zip
                                        Code</label>
                                    <!-- <div *ngIf="!EditMode && FirmDetails.People">{{FirmDetails.Addresses}}</div> -->
                                    <div class="col-md-3">
                                        <kendo-dropdownlist style="width:100%" [data]="cities" [defaultItem]=""
                                            [valuePrimitive]="true" formControlName="city" [defaultItem]=""
                                            [filterable]="true" textField="Name" valueField="Id"></kendo-dropdownlist>
                                    </div>

                                    <div class="col-md-2">
                                        <input class="form-control" id="{{'zipCodeId' + i}}" type="number"
                                            placeholder="Zip Code" formControlName="zipCode">
                                    </div>
                                </div>

                                <div class="form-group row">
                                        <label class="col-md-1 col-form-label header" attr.for="{{'phoneId' + i}}">Line
                                            3</label>
                                        <div class="col-md-9">
                                            <input class="form-control" id="{{'phoneId' + i}}" type="text"
                                                placeholder="Phone" formControlName="phone">
                                        </div>
                                    </div>

                            </div>
                        </div>
                        <div *ngIf="EditMode">
                            <button (click)="addAddress()">Add Address</button>
                        </div>
                    </div>
                </div>


                <div class="form-group row">
                    <div class="col-md-12" style="padding-top:10px;padding-left: 0px;padding-right: 30px;">
                        <div class="desc-header">Firm History</div>
                        <div class="divEditor">
                            <ckeditor [editor]="Editor" [id]="'ckFirmHistory'" *ngIf="EditMode"
                                formControlName="firmHistory" style="font-size: 11px;" debounce="500"
                                [config]="EditorConfig">
                            </ckeditor>
                            <div style="padding: 10px" *ngIf="!EditMode" [innerHTML]="FirmDetails.Firm.HISTORY_HTML">
                            </div>
                        </div>
                    </div>
                </div>



            </div>
            <div class="btn-toolbar" style="padding-top:40px;">
                <span> <button class="btn btn-default btn mr-3">
                        <i class="fa fa-file-pdf-o"></i>
                        Download Template
                    </button>
                </span>
                <span> <button class="btn btn-default btn mr-3">
                        <i class="fa fa-th-large"></i>
                        Upload Template Data
                    </button>
                </span>
                <span *ngIf="EditMode"><button type="button" class="btn btn-primary btn-view-all btn mr-3"
                        (click)="saveManager()">Save</button>

                </span>
                <span><button type="button" class="btn btn-primary btn-view-all btn mr-3"
                        (click)="cancelManager">Cancel</button>
                </span>
                <span><button type="button" style="float: right;" class="btn btn-primary btn-view-all"
                        (click)="deleteManager()">Delete</button>
                </span>
            </div>
        </form>
    </div>
</div>

组件

import { Component, Injectable, NgZone, ViewEncapsulation, ViewChild, Input } from '@angular/core';
import { OnInit } from '@angular/core';
import { FirmService } from '../services/firm.service';
import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import { CommonDataService } from '../services/common.data.service';
import { FormGroup, FormControl, FormBuilder, FormArray } from '@angular/forms';
import { ListItem } from '../models/listItem';


@Component({
    selector: 'mgr-firm',
    templateUrl: './firm.component.html'
})

export class FirmComponent implements OnInit {
    private Error: string;
    public FirmDetails: any;
    public EditMode: boolean;
    public Editor = ClassicEditor;
    public EditorConfig: string;
    public events: string[] = [];
    @Input() FirmId: number;
    DateFoundedDate: Date;
    public frmFirm: FormGroup;

    constructor(private _fb: FormBuilder, private firmService: FirmService, private commonDataService: CommonDataService) {

    }

    ngOnInit() {
        this.initializeFormModel();
        this.getFirmDetails();
    }


    initializeFormModel() {
        this.frmFirm = this._fb.group({
            firmName: [''],
            shortName: [''],
            alternateName: [''],
            dateFounded: [''],
            intraLinks: this._fb.array([
                this.createCredentials()
            ]),
            firmHistory: [''],
            People: [''],
            websites: this._fb.array([
                this.createWebsite()
            ]),
            addressess: this._fb.array([
                this.createAddress()
            ])
        });
    }



    public addWebsite(): void {
        this.websites.push(this.createWebsite());
    }

    public removeWebsite(index: number): void {
        const websites = this.frmFirm.get('websites') as FormArray;
        websites.removeAt(index);
    }

    private createWebsite(): FormGroup {
        return this._fb.group({
            websiteUrl: [''],
            username: [''],
            password: ['']
        });
    }



    public addAddress(): void {
        this.addressess.push(this.createAddress());
    }

    public removeAddress(index: number): void {
        const addressess = this.frmFirm.get('addressess') as FormArray;
        addressess.removeAt(index);
    }

    private createAddress(): FormGroup {
        return this._fb.group({
            city: [''],
            street: [''],
            line2: [''],
            line3: [''],
            zipCode: [''],
            phone: ['']
        });
    }


    public addCredentials(): void {
        this.intraLinks.push(this.createCredentials());
    }

    public removeCredentials(index: number): void {
        const intraLinks = this.frmFirm.get('intraLinks') as FormArray;
        intraLinks.removeAt(index);
    }

    private createCredentials(): FormGroup {
        return this._fb.group({
            intraUsername: [''],
            intraPassword: ['']
        });
    }



    get websites(): FormArray {
        return <FormArray>this.frmFirm.get('websites');
    }

    get addressess(): FormArray {
        return <FormArray>this.frmFirm.get('addressess');
    }

    get intraLinks(): FormArray {
        return <FormArray>this.frmFirm.get('intraLinks');
    }

    get cities(): ListItem[] {
        return JSON.parse(this.FirmDetails.LongCitiesJson).map(x => new ListItem(x.CITY_ID, x.CITY_NAME, null));
    }

    setFormValues(FirmDetails: any) {
        this.frmFirm.patchValue({
            firmName: FirmDetails.Firm.NAME,
            shortName: FirmDetails.Firm.SHORT_NAME,
            alternateName: FirmDetails.Firm.ALTERNATE_NAME,
            dateFounded: this.getDate(FirmDetails.Firm.DATE_FOUNDED),
            firmHistory: FirmDetails.Firm.HISTORY_HTML,
            People: FirmDetails.People
           // websites: FirmDetails.Websites,
           // addressess: FirmDetails.Addresses
        });
        const websiteGroup = this._fb.group({
           // websiteUrl: FirmDetails.Websites[0].WEBSITE_URL,
            //username: FirmDetails.Websites[0].USERNAME,
            //password: FirmDetails.Websites[0].PASSWORD
              websites: FirmDetails.Websites
        });
        this.frmFirm.setControl('websites', this._fb.array([websiteGroup]));
        const addressGroup = this._fb.group({
            city: this.FirmDetails.LongCitiesJson,
              addressess: FirmDetails.Addresses
            // street: FirmDetails.Firm.Addresses[0].LINE1,
            // line2: FirmDetails.Firm.Addresses[0].LINE2,
            // line3: FirmDetails.Firm.Addresses[0].LINE3,
            // zipCode: FirmDetails.Firm.Addresses[0].POSTAL_CODE,
            // phone: FirmDetails.Firm.Addresses[0].SWITCHBOARD_INT
        });
        this.frmFirm.setControl('addressess', this._fb.array([addressGroup]));
       const intraLinksGroup = this._fb.group({
            intraUsername: FirmDetails.Intralinks[2].USERNAME,
            intraPassword: FirmDetails.Intralinks[2].PASSWORD
        });
        this.frmFirm.setControl('intraLinks', this._fb.array([intraLinksGroup]));
    }


    getFirmDetails() {
        if (this.FirmId != null) {
            this.firmService.getFirmDetails(this.FirmId)
                .subscribe(data => {
                    this.FirmDetails = data;
                    this.setFormValues(this.FirmDetails);
                },
                    err => {
                        this.Error = 'An error has occurred. Please contact BSG';
                    },
                    () => {
                    });
        }
    }

    get dateFoundedDate(): string {
        const dateString = this.FirmDetails.Firm.DATE_FOUNDED;
        const results =parseInt(dateString.replace(/\/Date\(([0-9]+)[^+]\//i, "$1"));
        const date = new Date(results);
        const month = date.toLocaleString('en-us', { month: 'long' });
        return (month  + '-' + date.getFullYear());
    }

    private getDate(dateFounded: string): Date {
        const results =parseInt(dateFounded.replace(/\/Date\(([0-9]+)[^+]\//i, "$1"));
        const date = new Date(results);
        return new Date (date.getFullYear() + '-'  + (date.getMonth() + 1) + '-' + date.getDate());
    }

    saveManager() {
        this.firmService.createFirm(this.FirmDetails)
            .subscribe(data => {
                this.getFirmDetails();
                this.EditMode = !this.EditMode;
            },
                err => {
                    this.Error = 'An error has occurred. Please contact BSG';
                },
                () => {
                });
    }

    dateFoundedChanged(dateFoundedDate: Date) {
        this.DateFoundedDate = dateFoundedDate;
    }
}

地址数组

enter image description here

网站阵列

enter image description here

2 个答案:

答案 0 :(得分:0)

您的FirmDetails.Websites FirmDetails.addresses和表单数组表单控件名称中的属性名称不匹配。这就是为什么在绑定整个数组时会出现错误。

您应该通过创建函数和映射对象来修改数组

websitesMap = {
     WEBSITE_URL: 'websiteUrl',
     USERNAME: 'username',
     PASSWORD: 'password'
   };

addressesMap = {
     LINE1: 'line1',
     LINE2: 'line2',
     LINE3: 'line3',
     POSTAL_CODE: 'zipCode',
     SWITCHBOARD_INT: 'phone'
 }



modifyFormGroupValues(arr, mapObj) {
  let modifiedArr = [];
  arr.forEach((obj) => {
    let modifiedObj = {};
    for(let prop in obj) {
      modifiedObj[mapObj[prop]] = obj[prop];
    }
    modifiedArr.push(modifiedObj);
  }
  return modifiedArr;
}

 const websiteGroup = this._fb.group({
       websites: this.modifyFormGroupValues(FirmDetails.Websites, websitesMap)
 });

 const addressGroup = this._fb.group({
       addressess: this.modifyFormGroupValues(FirmDetails.Addresses,addressesMap)
 });

答案 1 :(得分:0)

我能够在您的代码中进行一些编辑, Stackblitz https://stackblitz.com/edit/angular-nwboxb我在这里使用了map函数,如下所示,并将值设置为表单组。

  const addressGroup = FirmDetails.Firm.ADDRESSES.map(address => {
  return this._fb.group({
        street: [address.LINE1],
        line2: [address.LINE2],
        line3: [address.LINE3],
        phone: [address.SWITCHBOARD_INT]
    });
  })
const addressFormArray: FormArray = this._fb.array(addressGroup);
this.frmFirm.setControl('addressess', addressFormArray);

希望这就是您的期望。