1

我正在尝试使用具有动态表单数据初始化的反应式表单来实现对话框。该对话框位于一个子组件中,由我的主组件触发。

当我尝试预选/填充表单组件时,出现此错误:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'status-success: false'. Current value: 'status-success: true'.

仅当我使用值预选 nb-datepicker 组件时才会出现问题,如果使用 null 作为值,一切都很好。

这是我的代码:

主要成分

<i (click)="editdialog.bookingToEdit(booking)" class="fas fa-edit"></i>
....
<ngx-booking-edit #editdialog></ngx-booking-edit>

带有对话框的子组件

@Component({
  selector: 'ngx-booking-edit',
  templateUrl: './booking-edit.component.html',
  styleUrls: ['./booking-edit.component.scss'],
})
export class BookingEditComponent implements AfterViewInit {

  @Output() updateBookingData = new EventEmitter<Booking>();
  @ViewChild('dialogedit') editDialog: TemplateRef<any>;

  private initialData: InitialDataResponse;
  private booking: Booking;
  public bookingForm: FormGroup;
  public newContractPartner = false;

  constructor(private formBuilder: FormBuilder,
              private  dialogService: NbDialogService,
              private initialDataService: InitialDataService,
              private toasterService: ToasterService) {
  }

  ngAfterViewInit() {
    this.loadInitData();

  }

  private loadInitData() {

    // REST call init data
    this.initialDataService.getInitalData()
      .map(resp => resp)
      .subscribe(
        (data) => {
          this.initialData = data.body;
        },
        (err) => {
          console.error('status', err.status);
        },
      );
  }

  //this method is called from the main component with an booking object
  bookingToEdit(bookingToEdit: Booking) {
    this.booking = bookingToEdit;
    this.initForm();

    this.dialogService.open(this.editDialog, {});
  }

  private initForm() {

    const today: Date = new Date();
    this.bookingForm = this.formBuilder.group({
      description: [this.booking.description, [Validators.required, MyValidators.nospaceValidator]],
      amount: [this.booking.amount, [Validators.required, MyValidators.validateAmount]],
      date: [today, Validators.required],
      capitalSource: [this.booking.capitalSource.id, Validators.required],
      category: [this.booking.subcategory.id, Validators.required],
      contractpartner: [this.booking.contractPartner.name, [Validators.required, MyValidators.nospaceValidator]],
      privatCheckbox: [this.booking.privatBookingOfUser],
    });

  }


}

子对话框模板

<toaster-container></toaster-container>
<ng-template #dialogedit let-data let-ref="dialogRef">
  <form [formGroup]="bookingForm">
    <nb-card>
      <nb-card-header>Buchung bearbeiten</nb-card-header>
      <nb-card-body>


        <div class="row">

          <div class="col-md-3">
            <div class="form-group">
              <div class="input-group input-group-sm">
                <input nbInput fullWidth
                       placeholder="Buchungsdatum"
                       formControlName="date"
                       style="line-height: 1rem;"
                       [ngClass]="{
                                                'status-danger': bookingForm.controls.date.invalid && bookingForm.controls.date.dirty,
                                                'status-success': bookingForm.controls.date.valid && bookingForm.controls.date.dirty }"
                       [nbDatepicker]="formpicker">
                <nb-datepicker #formpicker></nb-datepicker>
              </div>
            </div>
          </div>

          <div class="col-md-6">
            <div class="form-group input-group-sm">
              <input [ngClass]="{
                                  'status-danger': bookingForm.controls.description.invalid && bookingForm.controls.description.dirty,
                                  'status-success': bookingForm.controls.description.valid && bookingForm.controls.description.dirty }"
                     class="status" fullWidth id="description" nbInput placeholder="Beschreibung"
                     formControlName="description" type="text"/>
            </div>
          </div>


          <div class="col-md-2">
            <div class="form-group input-group-sm">
              <input [ngClass]="{
                                  'status-danger': bookingForm.controls.amount.invalid && bookingForm.controls.amount.dirty,
                                  'status-success': bookingForm.controls.amount.valid && bookingForm.controls.amount.dirty }"
                     class="status" fullWidth nbInput step="0.10" type="number"
                     formControlName="amount"
                     placeholder="Betrag" type="text"/>

            </div>
          </div>


        </div>
        <div class="row">


          <div class="col-md-5">
            <div class="form-group input-group-sm">
              <input nbInput fullWidth id="typeahead-format" placeholder="Vertragspartner"
                     formControlName="contractpartner"
                     type="text" placeholder="Vertragspartner"
                     [ngClass]="{
                                  'newContractPartner': newContractPartner,
                                  'status-danger': bookingForm.controls.contractpartner.invalid && bookingForm.controls.contractpartner.dirty,
                                  'status-success': bookingForm.controls.contractpartner.valid && bookingForm.controls.contractpartner.dirty }"
                     [ngbTypeahead]="searchContractPartner" class="status"/>
            </div>
          </div>

          <div class="col-md-4">
            <div class="form-group input-group-sm">
              <nb-select nbSelect fullWidth [size]="formSize"
                         formControlName="category" placeholder="Kategorie"
                         [ngClass]="{
                                  'status-danger': bookingForm.controls.category.invalid && bookingForm.controls.category.dirty,
                                  'status-success': bookingForm.controls.category.valid && bookingForm.controls.category.dirty }">
                <option disabled [value]=null>Kategorie</option>
                <nb-option-group *ngFor="let category of initialData?.categories" title="{{category.name}}">
                  <nb-option *ngFor="let subcategory of category.subcategories" [value]="subcategory.id">
                    {{subcategory.name}}
                  </nb-option>
                </nb-option-group>
              </nb-select>
            </div>
          </div>

          <div class="col-md-3">
            <div class="form-group input-group-sm">
              <nb-select fullWidth [size]="formSize"
                         formControlName="capitalSource"
                         [ngClass]="{
                                  'status-danger': bookingForm.controls.capitalSource.invalid && bookingForm.controls.capitalSource.dirty,
                                  'status-success': bookingForm.controls.capitalSource.valid && bookingForm.controls.capitalSource.dirty }">
                <nb-option disabled [value]=null>Kapitalquelle</nb-option>
                <nb-option *ngFor="let capitalSource of initialData?.capitalSources" [value]="capitalSource.id">
                  {{capitalSource.description}}
                </nb-option>
              </nb-select>
            </div>
          </div>

          <div class="col-md-2">
            <div class="form-group input-group-sm" style="color: #a1a1e5 !important;">

              <nb-checkbox formControlName="privatCheckbox">Privat</nb-checkbox>
            </div>
          </div>
        </div>


      </nb-card-body>
      <nb-card-footer>
        <div class="col-md-12">
          <div class="form-group input-group-sm">
            <div _ngcontent-c40="" class="container-btn">
              <button [disabled]="!bookingForm.valid" nbButton>
                Buchung speichern
              </button>
            </div>

          </div>
        </div>
      </nb-card-footer>
    </nb-card>
  </form>
</ng-template>

我尝试在 setTimeout 中调用 dialog.open 方法,并尝试在 resolvePromise.then(() => {...} 中预填充表单数据,但没有成功。

有谁知道问题出在哪里?

StackBlitz:stackblitz.com/edit/github-lv7hp3

4

1 回答 1

0

change detection更改后显式运行。请在您的组件中添加这段代码,这应该可以解决您的问题。

import { ChangeDetectorRef } from '@angular/core';

constructor(private cdRef:ChangeDetectorRef) {}

ngAfterViewChecked()
{
  this.cdRef.detectChanges();
}

Angular 文档链接 => https://angular.io/api/core/ChangeDetectionStrategy

GitHub问题=> https://github.com/angular/angular/issues/15634

于 2019-10-19T15:09:31.127 回答