我正在使用反应形式开发角度为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;
}
}
}
答案 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">
向该组件添加一个方法,该方法将针对数组中的所有其他控件将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>