Twoway数据绑定形式异常



嗨,我在我的表格上遇到以下错误

EXCEPTION: Expression has changed after it was checked. Previous value: 'Advertising'. Current value: 'Contractors'.

这是我的HTML表格

<form [formGroup]='billTypesForm' (ngSubmit)="submitForm(billTypesForm.value)">
    <table>
      <thead>
      <tr>
        <th>name</th>
        <th>percentage</th>
        <th>out of scope</th>
        <th>Edit</th>
      </tr>
      </thead>
      <tbody>
      <tr *ngFor='let billType of billTypes; let i = index'>
        <input type="hidden" name="id" [(ngModel)]="billType.id" [formControl]="billTypesForm.controls['id']" />
        <td class="name">
          <div class="input-field">
            <input type="text" name="name" placeholder="Name" [(ngModel)]="billType.name" [formControl]="billTypesForm.controls['name']" />
          </div>
        </td>
        <td class="percentage">
          <div class="input-field">
            <input type="text" name="percentage"  [(ngModel)]="billType.percentage" readonly placeholder="Tax" [formControl]="billTypesForm.controls['percentage']" />
          </div>
        </td>
        <td class="outOfScope">
          <input type="checkbox" name="outOfScope"  [(ngModel)]="billType.outOfScope"  [formControl]="billTypesForm.controls['outOfScope']" />
        </td>
        <input type="hidden" name="active" [(ngModel)]="billType.active"  [formControl]="billTypesForm.controls['active']" />
        <td class="edit" onclick="deleteBillTypeRow($(this));">
          <i class="material-icons">mode_edit</i>
        </td>
      </tr>
      </tbody>
    </table>
  </form>

问题似乎是围绕[(ngmodel)] =" billtype.name"的输入文本框

这是我的组件

    import {Component, OnInit, AfterViewInit, AfterContentChecked, Input} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms'
import {BillTypesDataService} from './bill-types-data.service'
import {BillTypes} from "./bill-types";
@Component({
  selector: 'brightbook-bill-types',
  templateUrl: './bill-types.component.html',
  styleUrls: ['./bill-types.component.css'],
})
export class BillTypesComponent implements OnInit {
  billTypesForm : FormGroup;
  public billTypes: BillTypes;
  constructor(private billTypesService: BillTypesDataService, fb: FormBuilder) {
    this.billTypesForm = fb.group({
        'id':[''],
        'name':[''],
        'percentage':[''],
        'outOfScope':[''],
        'active':['']
    });
  }
  ngOnInit() {
    this.billTypesService.getBillTypes()
    .subscribe(
      (res:BillTypes) => this.billTypes = res,
      error =>  console.log( <any>error)
    );
  }

这是我的服务

import { Injectable } from '@angular/core';
import {Http, Response, Request, RequestMethod} from '@angular/http';
import {BillTypes} from './bill-types'
import {Observable} from "rxjs";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class BillTypesDataService {
  private billTypesUrl = '/settings/bill-types/json';
  billTypes: BillTypes[] = [];
  constructor(public http: Http) {
  }
  getBillTypes() {
    return this.http.get(this.billTypesUrl)
      .map(res => <BillTypes[]> res.json())
      .catch(this.handleError);
  }
  private handleError (error: Response) {
    return Observable.throw('Internal server error');
  }
}

这是我从终点调用

回来的JSON
[
  {
    "id": null,
    "name": "Advertising",
    "percentage": 0.5,
    "outOfScope": false,
    "active": true,
    "created": null
  },
  {
    "id": null,
    "name": "Car & Truck Expenses",
    "percentage": 1,
    "outOfScope": false,
    "active": true,
    "created": null
  },
  {
    "id": null,
    "name": "Contractors",
    "percentage": 0,
    "outOfScope": false,
    "active": true,
    "created": null
  }
]

我有一个看起来像这样的模型类

export class BillTypes {
  constructor(
  public id:string,
  public name:string,
  public percentage:number,
  public outOfScope:boolean,
  public active:boolean,
  public dateCreate:string,
  ){}
}

如果有人能提供帮助,这将是非常感谢的。

我认为,您的表格疯狂。您为每个字段this.billTypesForm = fb.group({})创建了1个实例,然后为每行使用相同字段。尝试为每一行创建新的FormGroup ...

更新:

@Component({
    selector: 'brightbook-bill-types',
    templateUrl: './bill-types.component.html',
    styleUrls: ['./bill-types.component.css'],
})
export class BillTypesComponent implements OnInit {
    public billTypes: BillTypes;
    constructor(private billTypesService: BillTypesDataService){}
    ngOnInit() {
        this.billTypesService.getBillTypes()
        .subscribe(
             (res:BillTypes) => this.billTypes = res,
             error =>  console.log( <any>error)
        );
    }
}
@Component({
    selector: 'brightbook-bill-item',
    templateUrl: './bill-item.component.html'
})
export class BrItem{
    billTypesForm : FormGroup;
    @Input()billType: BillType;
    constructor(fb: FormBuilder){
        this.billTypesForm = fb.group({
            'id':[''],
            'name':[''],
            'percentage':[''],
            'outOfScope':[''],
            'active':['']
        });
    }
}

bill-Item.component.html

<tr>
<form [formGroup]='billTypesForm' (ngSubmit)="submitForm(billTypesForm.value)">
    <input type="hidden" name="id" [(ngModel)]="billType.id" [formControl]="billTypesForm.controls['id']" />
        <td class="name">
           <div class="input-field">
             <input type="text" name="name" placeholder="Name" [(ngModel)]="billType.name" [formControl]="billTypesForm.controls['name']" />
          </div>
        </td>
        <td class="percentage">
           <div class="input-field">
             <input type="text" name="percentage"  [(ngModel)]="billType.percentage" readonly placeholder="Tax" [formControl]="billTypesForm.controls['percentage']" />
          </div>
        </td>
    ...
</form>
</tr>

bill-types.component.html

<table>
  <thead>
  <tr>
    <th>name</th>
    <th>percentage</th>
    <th>out of scope</th>
    <th>Edit</th>
  </tr>
  </thead>
  <tbody>
     <bill-item [billType]="billType" *ngFor='let billType of billTypes;'></bill-item>
  </tbody>
</table>

最新更新