无法为选定的单选按钮发送真/假值,应单击它们两次以提交适当的值-Angular5 表



我正在尝试将每行单选按钮的选定值填充为真或假,并形成要提交的对象。 为了区分每行单选按钮的值,已给出导致问题的单选按钮标签的值{{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> &nbsp;&nbsp;{{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> 
        &nbsp;&nbsp;{{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

最新更新