TLDR: How to use FormArray or FormGroup with multiple file-input fields?
Hello everyone,
I want to build an event manager with Angular. Each event has a title, description, image and a flyer. The image is a png or jpg file-input and the flyer is a pdf one.
I need a toolbar performing the following actions:
- add should append a new event to the list withouth image or pdf
- delete should remove all selected event
- save should update to the database the event and load the two file-inputs files.
The list of event look like:
But I struggle to implement the form.
How can I use multiple file-input into a dynamic form with angular?
This is what I tried to do (event = promotion):
HTML:
  <form [formGroup]="promotionForm" *ngFor="let promotion of promotions; let i = index;">
    <div class="card" *ngIf="promotion.displayed" (click)="promotion.selected = !promotion.selected;">
      <div>
        <h2>Title</h2>
        <input matInput [(ngModel)]="promotion.title" [ngModelOptions]="{standalone: true}"/>
      </div>
      <div>
        <h2>Subtitle</h2>
        <input matInput [(ngModel)]="promotion.subtitle" [ngModelOptions]="{standalone: true}"/>
      </div>
      <div>
        <h2>Language</h2>
        <mat-select [(value)]="promotion.language"></mat-select>
      </div>
      <div class="description">
        <h2>Description</h2>
        <textarea matInput cdkAutosizeMinRows="5" [(ngModel)]="promotion.description"></textarea>
      </div>
      <div class="img">
        <div class="container">
          <h2>Image</h2>
          <mat-form-field>
            <ngx-mat-file-input formControlName="image" [multiple]="false" accept="image/webp, image/jpeg, image/png">
              <mat-icon ngxMatFileInputIcon>folder</mat-icon>
            </ngx-mat-file-input>
          </mat-form-field>
        </div>
        <img src="{{promotion.image}}">
      </div>
      <div class="pdf">
        <h2>PDF</h2>
        <mat-form-field>
          <ngx-mat-file-input formControlName="pdf" [multiple]="false" accept="application/pdf">
            <mat-icon ngxMatFileInputIcon>folder</mat-icon>
          </ngx-mat-file-input>
        </mat-form-field>
      </div>
      <mat-checkbox class="checkbox" [checked]="promotion.selected"></mat-checkbox>
    </div>
  </form>
TS:
promotions: Promotion[] = [];
  maxSize: number = 2; //Mo
  promotionForm: FormGroup;
  images: any[];
  pdfs: any[];
  constructor(private promotionService: PromotionService, private fb: FormBuilder) { }
  ngOnInit(): void {
    this.promotionForm = this.fb.group({
      image: [MaxSizeValidator(this.maxSize * 1024 * 1024)],
      pdf: [MaxSizeValidator(this.maxSize * 1024 * 1024)]
    })
    this.getAllPromotions();
  }
  getAllPromotions() {
    this.promotionService.getAllPromotions()
      .subscribe(promotions => {
        this.promotions = promotions.reverse();
        this.promotions.map(p => {
          p.selected = false;
          p.displayed = true;
        })
      })
  }
  deletePromotions() {
    let toDelete$ = this.promotions.filter(p => p.selected).map(p => { return this.promotionService.deletePromotion(p._id) });
    forkJoin(toDelete$).subscribe(() => this.getAllPromotions());
  }
  updatePromotions() {
    let toUpdate$ = this.promotions.filter(p => p.selected).map(p => { return this.promotionService.updatePromotion(p) });
    forkJoin(toUpdate$).subscribe(() => this.getAllPromotions());
  }
  selectAll() {
    if (this.promotions.filter(p => p.displayed).every(p => p.selected)) {
      this.promotions.map(p => p.selected = false)
    } else {
      this.promotions.filter(p => p.displayed).map(p => p.selected = true)
    }
  }
The issue with this solution is to get a unique file for each event. I want an unique file-input for each event and if I use FormGroup, I'm unable to have n file-input associated to each event. Should I use FormArrays of FormGroup and use image and pdf into each group?


