Невозможно отправить значения true / false для выбранных переключателей, и необходимо дважды щелкнуть их, чтобы отправить соответствующую таблицу значений Angular5. - PullRequest
0 голосов
/ 01 мая 2018

Я пытаюсь заполнить выбранные значения переключателей каждой строки как true или false и сформировать объект для отправки. Чтобы различать значения переключателей каждой строки, для тега переключателя было задано значение {{k}}+{{sizeobj.rbSelected}}, которое вызывает проблему, и обновление модели как k + false, затем k + k + false и т. Д. Для последующих щелчки. Проблема в логике в методе onSelectionChange(..). Предполагается, что onSelectionChange () обновляет JSON значениями true / false для выбранных переключателей каждой строки, чтобы иметь возможность отправить JSON обратно на сервер посредством вызова службы POST API.

Код:

    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;
        }
    }

Теперь я могу заполнить соответствующие значения true или false для выбранных переключателей в объекте JSON с указанными выше изменениями кода, что можно проверить по приведенной ниже ссылке, но все еще сталкивается с проблемой, т.е. щелкнуть каждый переключатель дважды, чтобы выбрать его. Благодарим вас за помощь в решении этой проблемы.

Рабочая плункерная ссылка: https://plnkr.co/edit/Nwz96APdaXdOXUuZ?preview

Ссылка на изображение макета экрана: Вложенная таблица с флажком и набором переключателей для каждой строки

PS: Мне нужно это с вышеупомянутым JSON или моделью данных (или, если нет, с минимально возможными изменениями, так как это трудно изменить), которое получается посредством вызова службы из серверной части.

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Я обнаружил исходную проблему с моим кодом. Вот исправление в 2 этапа:

я. Путь ngModel находится в нижнем фрагменте без назначения каких-либо значений, как раньше [(ngModel)]=sizeobj.rbSelected, позволяет переопределять значения, передаваемые ему из атрибута value={{k}}+{{sizeobj.rbSelected}}, и правильно назначать выбранные значения для sizeobj.rbSelected нашего объекта JSON.

<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, переданного ему обработчиком события (change), как показано в следующем фрагменте кода:

onSelectionChange(ev, i, j, k) {
    this.getItemCatalogs()[i].itemCatalog[j].itemSize[k].rbSelected = ev.target.checked;
..
}

Остальное весь код остается прежним. Вот рабочий Плункер: https://plnkr.co/edit/Nwz96APdaXdOXUuZ

0 голосов
/ 02 мая 2018

Хорошо, вот, пожалуйста. Я думаю, у меня есть решение для вас.

Чтобы достичь своей цели, вы должны временно добавить дополнительное поле в структуру вашего объекта для RadioButton-Interaction. Это поле получает удар перед передачей объекта обратно на сервер, чтобы не вызывать каких-либо исключений синтаксического анализатора.

FIRST : мы добавляем новое поле при запуске системы и вызываем это поле sharedValue

Для этого поместите следующий метод в ваш файл для ввода текста

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 () -.

SECOND : мы привязываем каждую радиокнопку группы к этому полю, а не привязываем ее к своему rbSelected -поле. Поле value вашего переключателя в 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 каждой радиокнопки.

THIRD : Если вы сделали свой выбор и хотите сохранить объект, вам нужно отбросить 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);
} 

ЧЕТВЕРТЫЙ : вызовите свой метод persist- / save- / store- или любой другой метод, который вызывается, чтобы отправить объект обратно на сервер.

Вот и все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...