[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;
  }
}
                    
                
                
            
        
浙公网安备 33010602011771号