[Angular] Update FormArray with patchValue

Currently, patchValue doesn't support update FormArray. 

The workarround is you need to empty the form array first, then add items back.

 

import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core';
import {FormBuilder, FormArray, FormGroup, FormControl, Validators} from '@angular/forms';
import {Meal} from '../../../shared/services/meals/meals.service';
@Component({
  selector: 'meal-form',
  changeDetection: ChangeDetectionStrategy.OnPush,
  styleUrls: ['meal-form.component.scss'],
  template: `
    <div class="meal-form">
      <form [formGroup]="form">
        <div class="meal-form__name">
          <label>
            <h3>Meal name</h3>
            <input type="text"
                   formControlName="name"
                   placeholder="e.g. English Breakfast">
            <div class="error" *ngIf="required">
              Workout name is required
            </div>
          </label>
        </div>

        <div class="meal-form__food">
          <div class="meal-form__subtitle">
            <h3>Food</h3>
            <button
              type="button"
              (click)="addIngredient()"
              class="meal-form__add">
              <img src="/img/add-white.svg" alt="Add food">
              Add food
            </button>
          </div>
          <div formArrayName="ingredients">
            <label *ngFor="let c of ingredients.controls; index as i;">
              <input type="text" [formControlName]="i" placeholder="e.g Eggs">
              <span
                class="meal-form__remove"
                (click)="removeIngredient(i)"
              ></span>
            </label>
          </div>

          <div class="meal-form__submit">
            <div>
              <button
                *ngIf="!exists"
                type="button" class="button" (click)="createMeal()">
                Create Meal
              </button>
              <button 
                *ngIf="exists"
                type="button" class="button" (click)="updateMeal()">
                Save
              </button>
              <a
                [routerLink]="['../']"
                class="button button--cancel">
                Cancel
              </a>
            </div>
            <div class="meal-form__delete" *ngIf="exists">
              <div *ngIf="toggled">
                <p>Delete item?</p>
                <button
                  class="confirm"
                  type="button"
                  (click)="removeMeal()">
                  Yes
                </button>
                <button
                  class="cancel"
                  type="button"
                  (click)="toggle()">
                  No
                </button>
              </div>

              <button
                class="button button--delete"
                type="button"
                (click)="toggle()">
                Delete
              </button>
            </div>
          </div>
        </div>
      </form>
    </div>
  `
})
export class MealFormComponent implements OnChanges {

  toggled = false;
  exists = false;

  @Input()
  meal: Meal;

  @Output()
  create = new EventEmitter<Meal>();

  @Output()
  update = new EventEmitter<Meal>();

  @Output()
  remove = new EventEmitter<Meal>();

  form = this.fb.group({
    name: ['', Validators.required],
    ingredients: this.fb.array([''])
  });

  get ingredients() {
    // Type check for ingredients, mark as FormArray
    // Therefore when we use 'ingredients',
    // We can get auto complete
    return this.form.get('ingredients') as FormArray;
  }

  get required() {
    return (
      this.form.get('name').hasError('required') &&
      this.form.get('name').touched
    );
  }

  constructor(private fb: FormBuilder) {

  }

  ngOnChanges(changes: SimpleChanges): void {
    if (this.meal && this.meal.name) {
      this.exists = true;

      this.emptyIngredients();

      const value = this.meal;
      this.form.patchValue(value);

      if (value.ingredients) {
        for (const item of value.ingredients) {
          this.ingredients.push(new FormControl(item));
        }
      }
    }
  }

  emptyIngredients() {
    while (this.ingredients.controls.length > 0) {
      this.ingredients.removeAt(0);
    }
  }

  createMeal() {
    if (this.form.valid) {
      this.create.emit(this.form.value);
    }
  }

  updateMeal() {
    if (this.form.valid) {
      this.update.emit(this.form.value);
    }
  }

  removeMeal() {
    this.remove.emit(this.form.value);
  }

  addIngredient() {
    // Add a new FormControl to FormArray
    this.ingredients.push(new FormControl(''));
  }

  removeIngredient(i: number) {
    this.ingredients.removeAt(i);
  }

  toggle() {
    this.toggled = !this.toggled;
  }
}

 

posted @ 2017-08-17 01:31  Zhentiw  阅读(5901)  评论(0编辑  收藏  举报