首页 > 解决方案 > Angular 6 反应形式。选择的FormArray

问题描述

我遵循了Angular Reative Form 指南,该指南解释了如何将地址的 FormArray 添加到 FormGroup。

现在我想要一个可以拥有不同能力的英雄,从 中选择它们select,或者更好地从select.

从 Angular Docs 的示例传递到我想要的功能,我无法让它运行。

这是我的 hero-form.ts

@Component({
  selector: 'app-hero-form',
  templateUrl: './hero-form.component.html',
  styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent implements OnInit, OnChanges {

  heroForm: FormGroup;
  nameChangeLog: string[] = [];
  hero: Hero = new Hero();
  allPowers: Power[] = [];

  constructor(private fb: FormBuilder, private powerService: PowerService) {
    this.createForm();
    this.logNameChange();
  }

  ngOnInit() {
    this.powerService.getAll().subscribe(powers => this.allPowers = powers);
  }

  createForm() {
    this.heroForm = this.fb.group({
      name: ['', Validators.required],
      powers: this.fb.array([]),
    });
  }

  ngOnChanges() {
    this.rebuildForm();
  }

  rebuildForm() {
    this.heroForm.reset({
      name: this.hero.name
    });
    this.setPowersControl(this.hero.powers);
  }

  setPowersControl(powers: Power[]) {
    const powersFGs = powers.map(pow => this.fb.group(pow));
    const powersFormArray = this.fb.array(powersFGs);
    this.heroForm.setControl('powers', powersFormArray);
  }


  get powers(): FormArray {
    const pows = this.heroForm.get('powers') as FormArray;
    return pows;
  }


  addPowerChoice() {
    this.powers.push(this.fb.control(new Power()));
    // this.powers.push(this.fb.group(new Power(), Validators.required));
  }

  onSubmit() {
    this.hero = this.prepareSaveHero();
    console.log('SAVING HERO', this.hero);
    // this.heroService.updateHero(this.hero).subscribe(/* error handling */);
    this.rebuildForm();
  }

  prepareSaveHero(): Hero {
    const formModel = this.heroForm.value;

    // deep copy of form model lairs
    const powersDeepCopy: Power[] = formModel.powers.map(
      (pow: Power) => Object.assign({}, pow)
    );

    // return new `Hero` object containing a combination of original hero value(s)
    // and deep copies of changed form model values
    const saveHero: Hero = {
      id: this.hero.id,
      name: formModel.name as string,
      // addresses: formModel.secretLairs // <-- bad!
      powers: powersDeepCopy
    };
    return saveHero;
  }

  revert() { this.rebuildForm(); }

  logNameChange() {
    const nameControl = this.heroForm.get('name');
    nameControl.valueChanges.forEach(
      (value: string) => this.nameChangeLog.push(value)
    );
  }

}

这是我的 hero-form.html

<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
    <div style="margin-bottom: 1em">
        <button type="submit" [disabled]="heroForm.pristine" class="btn btn-success">Save
        </button> &nbsp;
        <button type="button" (click)="revert()" [disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
    </div>

    <!-- Hero Detail Controls -->
    <div class="form-group">
        <label class="center-block">Name:
            <input class="form-control" formControlName="name">
        </label>
    </div>

    <div formArrayName="powers" class="well well-lg">
        <div *ngFor="let pow of powers.controls; let i=index" [formControlName]="i">
            <!-- The repeated power template -->
            <h4>Potere #{{i + 1}}</h4>
            <div style="margin-left: 1em;">

                <div class="form-group">
                    <label class="center-block">Power:
                        <select class="form-control">
                            <option *ngFor="let pow of allPowers" [value]="pow">{{pow.name}}</option>
                        </select>
                    </label>
                </div>

            </div>
            <br>
            <!-- End of the repeated address template -->
        </div>
        <button (click)="addPowerChoice()" type="button">Add a Power</button>
    </div>

</form>

<p>heroForm value: {{ heroForm.value | json}}</p>

<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>

这是只返回存根数据的电源服务

@Injectable({
  providedIn: 'root'
})
export class PowerService {

  constructor() {
  }

  getAll(): Observable<Power[]> {
    return of(this.getProds());
  }

  getProds(): Power[] {
    const powers = [];
    for (let i = 0; i < 10; i++) {
      const pow = new Power();
      pow.id = i+'';
      pow.name = 'Power ' + i;
      powers.push(pow);
    }
    return powers;
  }
}

这些是我的数据模型

export class Hero {
  id: number;
  name: string;
  powers: Power[];
}

export class Power {
  id: string = '';
  name: string = '';
}

在这里,我做了一个stackblitz 示例,但它不起作用

标签: angular6angular-reactive-forms

解决方案


我已经解决了

按照 Lucas Klaassen 的建议,我已经formControlName从on转移div到了select[value][ngValue]option

<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
  <div style="margin-bottom: 1em">
    <button type="submit"
            [disabled]="heroForm.pristine" class="btn btn-success">Save
    </button> &nbsp;
    <button type="button" (click)="revert()"
            [disabled]="heroForm.pristine" class="btn btn-danger">Revert
    </button>
  </div>

  <!-- Hero Detail Controls -->
  <div class="form-group">
    <label class="center-block">Name:
      <input class="form-control" formControlName="name">
    </label>
  </div>

  <div formArrayName="powers" class="well well-lg">
    <div *ngFor="let pow of powers.controls; let i=index">
      <!-- The repeated power template -->
      <h4>Potere #{{i + 1}}</h4>
      <div style="margin-left: 1em;">

        <div class="form-group">
          <label class="center-block">Power:
            <select class="form-control" [formControlName]="i">
              <option *ngFor="let pow of allPowers" [ngValue]="pow">{{pow.name}}</option>
            </select>
          </label>
        </div>

      </div>
      <br>
      <!-- End of the repeated address template -->
    </div>
    <button (click)="addPowerChoice()" type="button">Add a Power</button>
  </div>

</form>

<p>heroForm value: {{ heroForm.value | json}}</p>

<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>

然后我改变onSubmit()了添加一个英雄的构造函数调用如下

onSubmit() {
    this.hero = this.prepareSaveHero();
    console.log('SAVING HERO', this.hero);
    // this.heroService.updateHero(this.hero).subscribe(/* error handling */);
    this.hero = new Hero();
    this.rebuildForm();
}

然后我在类中添加了一个自定义构造Hero函数

export class Hero {
  id: number;
  name: string;
  powers: Power[];

  constructor() {
    this.id = 0;
    this.name = '';
    this.powers = [];
  }
}

现在它正在工作并在提交后正确重建表单


推荐阅读