我正在尝试将每行单选按钮的选定值填充为真或假,并形成要提交的对象。 为了区分每行单选按钮的值,已给出导致问题的单选按钮标签的值{{k}}+{{sizeobj.rbSelected}}
,并将模型更新为 k+false,然后是 k+k+false 等连续点击。 问题出在方法onSelectionChange(..)
逻辑上。onSelectionChange(( 应该使用每行所选单选按钮的真/假值更新 JSON,以便能够通过 POST API 服务调用将 JSON 提交回服务器。
法典:
import { Component, ChangeDetectorRef } from '@angular/core';
import {
FormsModule, AbstractControl, ControlValueAccessor, FormBuilder, FormGroup, Validators,
FormControl, NG_VALUE_ACCESSOR, Validator, NgForm
} from '@angular/forms';
@Component({
selector: 'my-app',
template: `
<table>
<tbody *ngFor="let redeempointdeliverable of redeempointsdata; let i=index;">
<tr>
<td>
<div class="form-group">
<input type="checkbox" name="allCB[{{i}}]" [checked]="isAllChecked(i)" (change)="checkAll($event, i)"
[(ngModel)]="redeempointdeliverable.mainCBChecked" required>
</div>
</td>
<td colspan="6">
</td>
</tr>
<tr *ngFor="let catalog of redeempointdeliverable.itemCatalog; let j=index;">
<td></td>
<td>
<div class="form-group">
<input [ngModelOptions]="{standalone: true}" type="checkbox" value="{{catalog.id}}"
[(ngModel)]="catalog.subCBChecked" [checked]="catalog.subCBChecked" (change)="checkSub($event, i, j)"
required>
</div>
</td>
<td></td>
<td *ngFor="let sizeobj of catalog.itemSize; let k=index;">
<div class="form-group">
<input type="radio" name={{catalog.itemType}}+{{j}}+{{i}} value={{k}}+{{sizeobj.rbSelected}}
[(ngModel)]=sizeobj.rbSelected [checked]="sizeobj.rbSelected"
(change)="onSelectionChange($event, i, j, k)"
required> {{sizeobj.size}}
</div>
{{sizeobj.rbSelected}}
</td>
<td></td>
</tr>
</tbody>
</table>
`
})
export class AppComponent {
name = 'Angular';
redeempointsdata: any;
constructor(private ref: ChangeDetectorRef) {
this.redeempointsdata = [
{
'itemCatalog': [
{
'itemSize': [
{
'size': 'SMALL',
'rbSelected': false
},
{
'size': 'MEDIUM',
'rbSelected': false
},
{
'size': 'LARGE',
'rbSelected': false
}
],
'subCBChecked': false
},
{
'itemSize': [
{
'size': 'SMALL',
'rbSelected': false
},
{
'size': 'MEDIUM',
'rbSelected': false
},
{
'size': 'LARGE',
'rbSelected': false
}
],
'subCBChecked': false
},
{
'itemSize': [
{
'size': 'SMALL',
'rbSelected': false
},
{
'size': 'MEDIUM',
'rbSelected': false
},
{
'size': 'LARGE',
'rbSelected': false
}
],
'subCBChecked': false
}
],
'mainCBChecked': false
},
{
'itemCatalog': [
{
'itemSize': [
{
'size': 'SMALL',
'rbSelected': false
},
{
'size': 'MEDIUM',
'rbSelected': false
},
{
'size': 'LARGE',
'rbSelected': false
}
],
'subCBChecked': false
}
],
'mainCBChecked': false
}
];
}
onSelectionChange(ev, i, j, k) {
this.getItemCatalogs()[i].itemCatalog[j].itemSize[k].rbSelected = ev.target.checked;
// this.ref.detectChanges();
for (let l = 0; l < this.redeempointsdata.length; l++) {
const rpObjAr = this.redeempointsdata[l].itemCatalog;
for (let m = 0; m < rpObjAr.length; m++) {
const sizeAr = rpObjAr[m].itemSize;
for (let n = 0; n < sizeAr.length; n++) {
const sizeObj = sizeAr[n];
console.log('sizeObj.rbSelected = ' + sizeObj.rbSelected);
if (n === k) {
continue;
} else if (n !== k) {
this.getItemCatalogs()[i].itemCatalog[j].itemSize[n].rbSelected = false;
}
}
}
}
}
getItemCatalogs() {
const rpData = [];
let rpObj = {};
for (let i = 0; i < this.redeempointsdata.length; i++) {
rpObj = this.redeempointsdata[i];
console.log('rpObj: ' + JSON.stringify(rpObj));
rpData.push(rpObj);
}
console.log('rpData: ' + JSON.stringify(rpData));
return rpData;
}
checkAll(ev, i) {
let count = 0;
this.getItemCatalogs()[i].itemCatalog.forEach(x => {
x.subCBChecked = ev.target.checked;
if (x.subCBChecked) {
count++;
}
});
console.log('count of checkboxes checked: ' + count);
return count;
}
isAllChecked(i) {
console.log('fired');
return this.getItemCatalogs()[i].itemCatalog.every(_ => _.subCBChecked);
}
checkSub(ev, i, j) {
let mainCheckVal = true;
const rpDataAr = this.getItemCatalogs();
const x = rpDataAr[i].itemCatalog;
for (j = 0; j < x.length; j++) {
if (x[j].subCBChecked === true) {
mainCheckVal = mainCheckVal && x[j].subCBChecked;
} else {
mainCheckVal = false;
}
}
this.getItemCatalogs()[i].mainCBChecked = mainCheckVal;
console.log('mainCheckVal: ' + mainCheckVal);
return mainCheckVal;
}
}
我现在能够使用上述代码更改为 JSON 对象中的选定单选按钮填充适当的 true 或 false 值,如下面的链接所示,但仍然面临一个问题,即需要单击每个单选按钮两次才能选择它。感谢在解决此问题方面的任何帮助。
工作 Plunker 链接: https://plnkr.co/edit/Nwz96APdaXdOXUuZ?preview
模拟屏幕的图像链接: 带有复选框和每行一组单选按钮的嵌套表
PS:我需要上面的JSON或数据模型(或者,如果没有,对它进行最小的可能更改,因为很难更改它(,这是通过后端的服务调用获得的。
好的,你去吧。我想我有一个解决方案给你。
为了实现您的目标,您必须临时向单选按钮交互的对象结构添加一个附加字段。此字段在将对象传输回服务器之前被踢出,以免导致任何解析器异常。
FIRST:当系统启动时,我们添加一个新字段并调用此字段 共享价值
为此,将以下方法放入您的打字稿文件中
private addFieldSharedValue(): void {
for (let l = 0; l < this.redeempointsdata.length; l++) {
const rpObjAr = this.redeempointsdata[l].itemCatalog;
for (let m = 0; m < rpObjAr.length; m++) {
// adding the field 'sharedValue' to each catalogue
rpObjAr[m].sharedValue = '0';
}
}
// debugging: printing a clone to show the intermediate state of the object
console.log('before: ', JSON.parse(JSON.stringify(this.redeempointsdata)));
}
通过添加字段 sharedValue 我默认将其设置为零。如果不分配值,则没有问题。然后,未定义初始值,并且不会预先选择组中的单选按钮。
在构造函数的最后(在实例化redeempointsdata
之后(调用此方法一次,或者简单地在 ngOnInit((-方法中调用此方法。
第二:我们将组的每个单选按钮绑定到此字段,而不是绑定它 到它自己的 rbSelected-field。 HTML 模板中单选按钮的值字段最初获取
k
的值。
<td *ngFor="let sizeobj of catalog.itemSize; let k=index;">
<div class="form-group">
<input type="radio" name={{catalog.itemType}}+{{j}}+{{i}} value={{k}}
[(ngModel)]="catalog.sharedValue" [checked]="catalog.sharedValue"
(change)="onSelectionChange($event, i, j, k)"
required>
{{sizeobj.size}}
</div>
{{sizeobj.rbSelected}}
</td>
现在发生的情况是,组的单选按钮仅更改 sharedValue 的值才能正常工作,而您的onSelectionChange()
方法现在能够按预期执行。因为它现在是唯一一个更改每个单选按钮的字段rbSelected
的人。
第三:如果你已经完成了选择,想要持久化对象,你必须事先删除 sharedValue。调用此方法以完成它。
private deleteFieldSharedValue() {
for (let l = 0; l < this.redeempointsdata.length; l++) {
const rpObjAr = this.redeempointsdata[l].itemCatalog;
for (let m = 0; m < rpObjAr.length; m++) {
// delete the field 'sharedValue' of each catalogue
delete rpObjAr[m].sharedValue;
}
}
// debugging: printing the final state of the object before sending it
console.log('after: ', this.redeempointsdata);
}
第四:调用您的持久/保存/存储或任何称为将对象发送回服务器的方法。
就是这样。
我发现了我的代码的原始问题。以下是 2 个步骤的修复:
我。ngModel
放置在下面的代码片段中的方式没有像以前那样分配任何值[(ngModel)]=sizeobj.rbSelected
允许它覆盖从 value={{k}}+{{sizeobj.rbSelected}}
属性传递给它的值,并将所选值正确分配给我们的 JSON 对象sizeobj.rbSelected
。
<input type="radio" name={{catalog.itemType}}+{{j}}+{{i}} value={{k}}+{{sizeobj.rbSelected}}
[checked]="sizeobj.rbSelected" (change)="onSelectionChange($event, i, j, k)"
ngModel required>
ii. 在onSelectionChange()
方法中,我们需要直接从事件处理程序传递给它的 event
object 参数(change)
为选定的单选按钮位置赋值,如以下代码片段所示:
onSelectionChange(ev, i, j, k) {
this.getItemCatalogs()[i].itemCatalog[j].itemSize[k].rbSelected = ev.target.checked;
..
}
其余所有代码保持不变。这是工作的Plunker:https://plnkr.co/edit/Nwz96APdaXdOXUuZ