Ошибка Angular FormArray patchValue: TypeError: value.forEach не является функцией - как устранить?

Страница изначально была написана как форма, управляемая шаблоном, но сейчас преобразуется в реактивную, чтобы добавить функцию автосохранения.

В конструкторе компонента страницы я определяю переменную реактивной формы:

 this.form = fb.group({
    reviewer: '',
    position: '',
    officeName: '',
    rows: fb.array([]),
    comments1: '',
    comments2: '',
    comments3: ''
});

«строки» - это поле, имеющее отношение к этой проблеме.

В ngInit через веб-API выполняется запрос на получение сохраненных данных формы. Данные извлекаются как массив строк, каждая из которых содержит массив из 6 ячеек. Третья ячейка будет привязана к FormControl, остальные будут отображаться как статический текст.

this.rows = summaryReportQuestion.map(summaryReportQuestionObj => {
    return {
        cells: [
            summaryReportQuestionObj.questionID,
            summaryReportQuestionObj.question,
            (summaryReportQuestionObj.columnSign == '$' ? (summaryReportQuestionObj.columnSign + ' ' + summaryReportQuestionObj.target) : summaryReportQuestionObj.target + ' ' + summaryReportQuestionObj.columnSign),
            (summaryReportQuestionObj.budget == null ? summaryReportQuestionObj.budget : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.budget), false) : summaryReportQuestionObj.budget + ' ' + summaryReportQuestionObj.columnSign)),
            (summaryReportQuestionObj.average == null ? summaryReportQuestionObj.average : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.average), false) : summaryReportQuestionObj.average + ' ' + summaryReportQuestionObj.columnSign)),
            (summaryReportQuestionObj.top20Percent == null ? summaryReportQuestionObj.top20Percent : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.top20Percent), false) : summaryReportQuestionObj.top20Percent + ' ' + summaryReportQuestionObj.columnSign))
        ]
    };
});

let faRows = new FormArray([]);
for (var i = 0, len = this.rows.length; i < len; i++) {
    let row = this.rows[i].cells;
    for (var j = 0, length = this.rows[i].cells.length; j < length; j++) {
        let fc = new FormControl(this.rows[i].cells[j]);
        faRows.push(fc);
    }
}

// this.form.setValue({rows: faRows});
// this.form.setControl('rows', faRows);

В HTML:

<tbody>
    <tr *ngFor="let row of rows;let r = index" [attr.data-index]="r">
        <ng-container>
            <td *ngFor="let cell of row.cells;let i = index" [attr.data-index]="i">
                <span *ngIf="i != 2">{{cell}}</span>
                <!-- <input type="text" formControlName="form.rows[r]" *ngIf="i == 2"> -->
            </td>
        </ng-container>
    </tr>
</tbody>

На основе комментария и ответа я разъяснил свое намерение и код. [спасибо @amal и @DeborahK] Сейчас я привязываю только одну ячейку данных из каждой строки к FormControl, а остальные ячейки в каждой строке отображаются с помощью: {{cell}}

Поэтому мне нужно отобразить содержимое this.rows (как показано в html), а также this.form.rows.

В настоящее время у меня возникают две проблемы с пониманием того, как это сделать. В машинописном тексте, оставляя последний блок циклов, повторяющих строки данных, которые создают строки, FormControls массив faRows содержит именно то, что я ожидал, FormArray из FormControls, и каждый из них получил правильное связанное сохраненное значение. Но при попытке скопировать данные из this.rows для создания FormControls для form.rows я не могу заставить setValue или setControl работать правильно. Это может быть связано с наименованием FormControl на странице html, что является моей второй проблемой.

Я не понимаю, как ссылаться на переменную формы для динамического создания formControlName в html. Это то, что я себе представляю, но это не работает.

 <input type="text" formControlName="form.rows[r]" *ngIf="i == 2">

Страница отображена как форма на основе шаблона


person lynnjwalker    schedule 29.09.2017    source источник
comment
Просто взглянув на код, я чувствую, что ваши назначения на инициализацию formArray неверны. Ожидаете ли вы иметь элемент управления formArray для каждого из элементов в пределах одной ячейки? Например, для questionId, question, columnSign, budget и т. Д.?   -  person amal    schedule 29.09.2017
comment
@amal: я изменил исходный код, потому что я не собираюсь иметь элемент управления formArray для каждого элемента в одной строке. Вместо этого только 1 элемент (третий, фактический) будет иметь связанный FormControl. Не могли бы вы объяснить, как я смешиваю два массива, а один реактивный нет?   -  person lynnjwalker    schedule 04.10.2017
comment
До сих пор не ясно, что вы хотите делать и что делаете не так. Если вы хотите сослаться на реактивный элемент управления formArray в шаблоне, вам также необходимо обратиться к formArrayName . Не могли бы вы создать репродукцию или показать, как вы хотите, чтобы эта страница выглядела в итоге (чего вы стремитесь достичь)?   -  person amal    schedule 04.10.2017


Ответы (1)


Насколько мне известно, невозможно вызвать .patchValue с помощью FormArray.

Моя форма настроена аналогично, где теги - это мой FormArray.

    this.productForm = this.fb.group({
        productName: ['', [Validators.required,
                           Validators.minLength(3),
                           Validators.maxLength(50)]],
        productCode: ['', Validators.required],
        starRating: ['', NumberValidators.range(1, 5)],
        tags: this.fb.array([]),
        description: ''
    });

При настройке данных для редактирования мне пришлось сделать следующее:

    this.productForm.patchValue({
        productName: this.product.productName,
        productCode: this.product.productCode,
        starRating: this.product.starRating,
        description: this.product.description
    });
    this.productForm.setControl('tags', this.fb.array(this.product.tags || []));

Я использовал patchValue для каждого из простых FormControls и setControl для FormArray.

Вы можете попробовать и посмотреть, решит ли это вашу проблему.

person DeborahK    schedule 30.09.2017
comment
К вашему сведению - patchValue действительно работает с FormArray, но он не будет изменять размер массива, поэтому он работает только в том случае, если данные, которые вы устанавливаете, имеют ту же длину, что и FormArray. (не очень полезно для этого вопроса, но кое-что отметить) - person Lenny; 09.10.2018
comment
Это действительно полезно. У меня есть вложенные группы форм, которые включают в себя массивы форм и т. Д., И на самом деле это довольно сложная форма. Я получал всевозможные ошибки и странное поведение, включая то, что массивы не обновлялись, а элементы управления становились недействительными или помечались как требуемые, хотя это не так. Этот ответ помог мне решить эту проблему. В конце концов, я использовал patchValue, но затем мне пришлось перебрать все элементы управления и использовать SetControl для каждого вложенного элемента управления. - person Henk Kruger; 22.02.2021