Angular 2 / PrimeNG - выражение изменилось после проверки. Привязка NgModel к последнему недопустимому элементу управления формой

У меня проблема, когда, когда у самого последнего элемента в моей форме есть значение, привязанное к нему, появляется ошибка «Выражение было изменено после того, как оно было проверено». брошен.

Я начну с того, что скажу, что это основано на примере веб-сайта Angular 2 здесь - https://angular.io/docs/ts/latest/cookbook/dynamic-form.html#!#top

Как работает мое приложение, я сначала создаю динамическую форму с элементами управления в моем компоненте формы на основе модели.

Мои компоненты формы html зацикливают вопросы в модели следующим образом

<form *ngIf="showForm" [formGroup]="formGroup">
    <!-- questions-->
    <div *ngIf="questions.length > 0">
        <div *ngFor="let question of questions">
            <question [question]="question" [formGroup]="formGroup"></question>
        </div>
    </div>
    <button pButton type="submit" label="Submit" icon="fa-check-circle-o" iconPos="left"
            [disabled]="!formGroup.valid" (click)="submitFinalForm()"></button>
</form>

Ниже представлен компонент вопроса html, который использует данные, переданные из компонента формы, для отображения определенных типов вопросов через ngSwitch.

<label [attr.for]="question.field">
    {{ question.question }}
</label>
<div [ngSwitch]="question.type">
    <!-- Radio / Checkbox -->
    <radio-checkbox-question *ngSwitchCase="1" [formGroup]="formGroup" [question]="question"></radio-checkbox-question>
</div>

Наконец, вот компонент радио-флажка-вопроса

<div *ngIf="showQuestion" [formGroup]="formGroup">
    <!-- Radio -->
    <div *ngIf="model.radiocheckbox == 'radio'">
        <div *ngFor="let label of model.labels; let i = index;">
             <p-radioButton name="{{model.field}}"
                            value="{{i}}"
                            label="{{label}}"
                            formControlName="{{model.field}}"
                            [(ngModel)]="questionAnswerRadio"></p-radioButton>
        </div>
    </div>
</div>

Вот собственно компонент TS

import { Component, Input, OnInit }         from "@angular/core";
import { FormGroup }                        from "@angular/forms";

import { RadioCheckboxQuestion }            from "../Questions/radio.checkbox.question.model";

@Component({
    selector: "radio-checkbox-question",
    templateUrl: "radio.checkbox.component.html"
})
export class RadioCheckboxComponent implements OnInit {

    @Input() question: any;
    @Input() formGroup: FormGroup;

    model: RadioCheckboxQuestion = new RadioCheckboxQuestion();
    showQuestion: boolean = false;

    questionAnswerRadio: string = "";

    ngOnInit(): void {
        // question essential properties
        if (this.question.hasOwnProperty("field") && this.question["field"] &&
            this.question.hasOwnProperty("labels") && this.question["labels"]) {
            this.model.field = this.question["field"];
            this.model.labels = this.question["labels"];

            // assume always radio for debugging
            this.model.radiocheckbox = "radio";

            // set existing answer
            if (this.question.hasOwnProperty("QuestionAnswer") && this.question["QuestionAnswer"]) {
                if (this.model.radiocheckbox == "radio") {
                    this.questionAnswerRadio = this.question["QuestionAnswer"];
                }
            }

            this.showQuestion = true;
        }
    }
}

Я также видел много проблем SO, таких как следующее Пример динамических форм Angular 2 с результатами ngmodel в выражении изменилось после его проверки, в котором в основном указано, что [(ngModel)] не следует использовать с динамическими формами, но в документации primeNG говорится, что компоненты могут работать с формы, управляемые моделями, и единственный способ установить ответ (о котором я знаю) - это [(ngModel)]. Я считаю, что здесь может произойти то, что я установил единственный вопрос в formGroup на значение, которое formGroup становится действительным между обнаружением изменения и вызывает ошибку

Error in ./FormComponent class FormComponent - inline template:17:48 caused by: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.


person user3333134    schedule 07.03.2017    source источник
comment
Вы также можете создать плункер?   -  person yurzui    schedule 07.03.2017
comment
Я не уверен, как сделать плункер последних версий Angular 2 и PrimeNG, кажется, что они устарели? Странно то, что в моем компоненте формы, если я импортирую ChangeDetectionStrategy, ChangeDetectorRef и использую changeDetection: ChangeDetectionStrategy.OnPush вместе с частным cd: ChangeDetectorRef и this.cd.markForCheck (); чтобы вручную обновить мой компонент формы, проблема больше не возникает, но в полной версии формы вводятся текстовые поля из PrimeNG, а кнопки переключателя / флажка - нет.   -  person user3333134    schedule 07.03.2017


Ответы (2)


Из вашего шаблона похоже, что вы используете как диск модели (formControlName), так и управляемый шаблоном (ngModel).

 <p-radioButton name="{{model.field}}"
                            value="{{i}}"
                            label="{{label}}"
                            formControlName="{{model.field}}"
                            [(ngModel)]="questionAnswerRadio"></p-
   <radioButton>

Выберите один из способов и попробуйте еще раз. Предлагаю вам удалить [(ngModel)]

person john Smith    schedule 21.11.2017

Единственный способ, который я нашел, чтобы получить удовлетворение от обнаружения изменений с моими мульти-вложенными компонентами и primeNG, - это реализовать полное обнаружение изменений вручную. В основном это означает, что в каждый компонент мне пришлось добавить что-то вроде следующего

import ChangeDetectorRef

constructor(private change: ChangeDetectorRef)
{}

ngOnInit() {

    // code here that inits everything
    this.change.markForCheck();
}

Все, что меньше, чем это, привело к тому, что ошибки обнаружения изменений выскакивали по-разному и уникальным образом в компонентах, которые использовали primeNG.

person user3333134    schedule 08.03.2017
comment
В некоторых моих случаях запоминание этого ответа помогло найти рабочий подход. - person Arnaud P; 11.10.2018