单选按钮切换不能以响应形式工作

时间:2019-03-07 12:51:52

标签: angular angular-reactive-forms

我正在使用反应形式开发角度为7的切换单选按钮功能。目前,单选按钮正在为每个表单数组渲染,但不会在数组之间切换。用户需要能够将地址之一设置为主地址。我已经尝试为单选按钮分配新的ID和值,但这并没有任何区别

UI

[![在此处输入图片描述] [1]] [1]

代码-根据JoséGazzano的评论更新代码

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

    .header {
        width: 8%;
    }


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

    .col-form-label {
        padding: 0%;
    }

    .scrollClass {
        height: 500px;
        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)="saveManager()">
            <div *ngIf="FirmDetails && FirmDetails.Firm" class="card-body scrollClass">

                <div class="form-group row">
                    <label for="inputName" class="col-sm-2 col-form-label modal-label header">Name</label>
                    <div class="col-md-9">
                        <div *ngIf="!EditMode">{{FirmDetails.Firm.NAME}}</div>
                        <input *ngIf="EditMode" kendoTextBox [readonly]="false" class="form-control"
                            formControlName="NAME" />
                    </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="SHORT_NAME" />
                    </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="ALTERNATE_NAME" />
                    </div>
                </div> -->

                <div class="form-group row">
                    <label for="inputEmail" class="col-sm-2 col-form-label modal-label header">Date Founded</label>
                    <div class="col-md-4">
                        <div *ngIf="!EditMode">{{dateFoundedDate}}</div>
                        <kendo-datepicker *ngIf="EditMode" [format]="'MMMM yyyy'"
                            (valueChange)="dateFoundedChanged($event)" formControlName="DATE_FOUNDED"
                            class="form-control">
                        </kendo-datepicker>
                    </div>
                </div>




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

                    </div>
                    <div class="col-md-9 offset-md-2">
                        <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-4">
                                        <input formControlName="WEBSITE_URL" class="form-control">
                                    </div>
                                    <div class="col-md-4">
                                        <input formControlName="USERNAME" class="form-control">
                                    </div>
                                    <div class="col-md-3">
                                        <input formControlName="PASSWORD" class="form-control">
                                    </div>
                                    <div class="col-md-1" *ngIf="EditMode">
                                        <button (click)="removeWebsite(i)">RM</button>
                                    </div>

                                </div>
                            </div>
                        </div>

                    </div>
                </div>
                <div class="form-group row" *ngIf="EditMode">
                    <div class="col-md-2 offset-md-2">
                        <button type="button" (click)="addWebsite()">Add Website</button>
                    </div>
                </div>


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



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

                    <div [formGroupName]="test">

                        <div class="form-group row">
                            <label class="col-md-2 col-form-label"> Primary Address
                            </label>
                            <div class="col-md-2">
                                <div class="form-check">
                                    <label class="form-check-label">
                                        <input class="form-check-input" id="primary1Id{{i}}" type="radio" value="home{{i}}"
                                            formControlName="IS_HEAD_OFFICE"> Home
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row">
                            <label class="col-md-2 col-form-label" attr.for="{{'street1Id' + i}}">Line 1
                            </label>
                            <div class="col-md-9">
                                <input class="form-control" id="{{'street1Id' + i}}" type="text"
                                    formControlName="LINE1">

                            </div>
                        </div>

                        <div class="form-group row">
                            <label class="col-md-2 col-form-label" attr.for="{{'street2Id' + i}}">Line 2
                            </label>
                            <div class="col-md-9">
                                <input class="form-control" id="{{'street2Id' + i}}" type="text"
                                    formControlName="LINE2">
                            </div>
                        </div>

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

                        <div class="form-group row" *ngIf="EditMode">

                            <div class="col-md-9 offset-md-2">
                                <button type="button" (click)="removeAddress(i)">Remove Address</button>
                            </div>

                        </div>


                    </div>

                </div>
                <div class="form-group row " *ngIf="EditMode">
                    <div class="col-md-2 offset-md-2">
                        <button type="button" (click)="addAddress()">Add Address</button>
                    </div>
                </div>

            </div>





            <div class="btn-toolbar" style="padding-top:40px;">

                <span *ngIf="EditMode"><button type="submit" class="btn btn-primary btn-view-all btn mr-3">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 originalContactList: any;
    public originalCityList: any;
    public events: string[] = [];
    @Input() FirmId: number;
    DateFoundedDate: Date;
    public frmFirm: FormGroup;
    public value: Date = new Date();



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

    }

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


    initializeFormModel() {
        this.frmFirm = this._fb.group({
            NAME: [''],
            SHORT_NAME: [''],
            ALTERNATE_NAME: [''],
            DATE_FOUNDED: [''],

            HISTORY_HTML: [''],
            People: [''],
            Websites: this._fb.array([
                this.createWebsite()
            ]),
            Addresses: 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;
        if (websites.length === 1)
        {
            websites.reset();
          return;
        }
        websites.removeAt(index);
    }


    private createWebsite(): FormGroup {
        return this._fb.group({
            WEBSITE_URL: [''],
            USERNAME: [''],
            PASSWORD: ['']
        });
    }



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



    public removeAddress(index: number): void {
        const addressess = this.frmFirm.get('Addresses') as FormArray;
        if (addressess.length === 1)
        {
          addressess.reset();
          return;
        }
        addressess.removeAt(index);
    }

    private createAddress(): FormGroup {
        return this._fb.group({
            // city: [''],
            LINE1: [''],
            LINE2: [''],
            LINE3: [''],
            // zipCode: [''],
            SWITCHBOARD_INT: ['']
        });
    }



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

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


    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({
            NAME: FirmDetails.Firm.NAME,
            SHORT_NAME: FirmDetails.Firm.SHORT_NAME,
            ALTERNATE_NAME: FirmDetails.Firm.ALTERNATE_NAME,
            DATE_FOUNDED: this.getDate(FirmDetails.Firm.DATE_FOUNDED),
            HISTORY_HTML: FirmDetails.Firm.HISTORY_HTML,
            People: FirmDetails.People

        });
      this.websites.patchValue(this.modifyFormGroupValues(FirmDetails.Websites, this.websitesMap))

     this.websites.patchValue(this.modifyFormGroupValues(FirmDetails.Websites, this.websitesMap)); 

     this.addressess.patchValue(this.modifyFormGroupValues(FirmDetails.Addresses,this.addressesMap))






        const addressGroup = FirmDetails.Firm.Addresses.map(address => {
            return this._fb.group({
                ID:    [address.ID],
                LINE1: [address.LINE1],
                LINE2:  [address.LINE2],
                LINE3:  [address.LINE3],
                SWITCHBOARD_INT:  [address.SWITCHBOARD_INT],
                IS_HEAD_OFFICE:  [address.IS_HEAD_OFFICE],
                CITY:  [address.CITY],
                CITY_ID:  [address.CITY_ID],
                POSTAL_CODE:  [address.POSTAL_CODE],
                FIRM_ID: [address.FIRM_ID]
            });
        });
        const addressFormArray: FormArray = this._fb.array(addressGroup);
        this.frmFirm.setControl('Addresses', addressFormArray);


        const websiteGroup = FirmDetails.Firm.Websites.map(website => {
           return this._fb.group({
            ID:    [website.ID],
            WEBSITE_URL: [website.WEBSITE_URL],
            USERNAME:   [website.USERNAME],
            PASSWORD:   [website.PASSWORD],
            FIRM_ID: [website.FIRM_ID]
            });
        });
        const wesbiteFormArray: FormArray = this._fb.array(websiteGroup);
        this.frmFirm.setControl('Websites', wesbiteFormArray);
    }

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

    get dateFoundedDate(): string {
        if (this.FirmDetails.Firm.DATE_FOUNDED != null) {
        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 {
        if (dateFounded != null) {
        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() {

        const result = Object.assign(this.FirmDetails.Firm, this.frmFirm.value);
        //this.FirmDetails.Firm = Object.assign({}, result.Firm);


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

    public keyContactChange(value: any): void {
        this.FirmDetails.Firm.KEY_CONTACT_ID = value;
    }

    public dateFoundedChanged(value: Date): void {
        this.FirmDetails.Firm.DATE_FOUNDED = value;
    }


    handleFilter(value) {
        if (value.length >= 1) {
            this.FirmDetails.People = this.originalContactList.filter((s) => s.FIRST_NAME.toLowerCase().indexOf(value.toLowerCase()) !== -1);
        } else {
            this.FirmDetails.People = this.originalContactList;
        }
    }


}

3 个答案:

答案 0 :(得分:3)

您以正确的方式设置formControlName,现在只需为每个单选按钮提供一个unic ID。

编辑: 而且您没有关闭输入标签。 我从<input type....> to <input type.../>

另一个重要提示: 当您使用Angular时,应将html划分为更小的组件。 您的html文件太长了,应该是。 例如,您的四组应该是由较小的组件组​​成的单个组件,例如,input + label。较小的组件必须接收使用表单所需的所有输入。 您可以详细了解如何进行in here

             <div class="form-group row">
                  <label class="col-md-2 col-form-label"> Primary Address   </label>
                  <div class="col-md-2">
                      <div class="form-check">
                          <label class="form-check-label">
                              <input class="form-check-input" id="primary1Id{{i}}" type="radio" value="home{{i}}"
                                  formControlName="IS_HEAD_OFFICE"/> <span>Home</span>
                          </label>
                      </div>
                  </div>
              </div>

答案 1 :(得分:3)

这里的问题是您的单选按钮分配了相同的值,因此它们被视为相同的输入。这就是为什么您不能在它们之间切换。

尝试为每个参数设置一个不同的值,它应该可以按预期工作,这也将有助于表单逻辑和验证;)

提醒一下,要使一组单选按钮在它们之间进行切换,您唯一需要做的就是为所有按钮设置相同的名称(或您的情况下为formControlName),当然还要设置不同的值。 请勿设置与先前建议的ID相同的ID,因为从HTML角度看,这在语义上是不正确的

这是一个最小的StackBlitz示例,您可以在其中进行尝试https://stackblitz.com/edit/angular-lvahzg?file=src%2Fapp%2Fapp.component.ts

它的所有单选按钮都具有相同的formContrlName和相同的值,请尝试为每个按钮设置不同的值,并查看其工作原理;)

编辑:使用反应形式https://angular.io/api/forms/RadioControlValueAccessor

添加有关单选按钮的Angular文档

编辑2:这是我在评论时谈论的问题

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

  <div [formGroupName]="i"> --> This formGroupName should be the same on each loop in order to make the radio buttons to toggle between them

                        <div class="form-group row">
                            <label class="col-md-2 col-form-label"> Primary Address
                            </label>
                            <div class="col-md-2">
                                <div class="form-check">
                                    <label class="form-check-label">
                                        <input class="form-check-input" id="primary1Id{{i}}" type="radio" value="home{{i}}"
                                            formControlName="IS_HEAD_OFFICE"> Home
                                    </label>
                                </div>
                            </div>
                        </div>

答案 2 :(得分:0)

我对您的要求的理解是,当用户将地址设置为“家庭”时,所有其他地址应取消设置作为“家庭”。如果我的理解是正确的,那么您使用原始代码的位置就正确了,但是有几件事需要更正。

表单组名

使用ngFor,您将为FormArray中的每个控件创建一个地址。 FormArray中的每个控件都是一个FormGroup,其名称是其在FormArray中的索引。所以当我有formGroupName时,您是正确的

所以回到此

<div [formGroupName]="i">

创建一个OnPrimaryToggleMethod

向该组件添加一个方法,该方法将针对数组中的所有其他控件将IS_HEAD_OFFICE设置为false

onPrimaryToggled(newValue: any, changedItem: FormControl) {
  if (newValue.returnValue === true) {
  const toChange = this.frmFirm.get('Addresses').controls.filter(el => el !== changedItem);
    toChange.forEach(el => el.patchValue({
      IS_HEAD_OFFICE: false
    }));
  }
}   

更新复选框以调用切换方法

将更改事件绑定添加到单选按钮以调用方法

(change)="onPrimaryToggled($event, item)"

现在它应该看起来像下面的代码(顺便说一句,您不需要value属性)

<div formArrayName="Addresses" *ngFor="let item of frmFirm.get('Addresses').controls; let i = index;">
     <div [formGroupName]="i">
           <div class="form-group row">
                <label class="col-md-2 col-form-label"> Primary Address </label>
                <div class="col-md-2">
                   <div class="form-check">
                      <label class="form-check-label">

                        <input
                            class="form-check-input" 
                            id="primary1Id{{i}}" 
                            type="radio" 
                            formControlName="IS_HEAD_OFFICE" 
                            (change)="OnPrimaryToggled($event, item)"
                        > Home

                      </label>
                    </div>
                 </div>
             </div>                        
      </div>
</div>