使用角度动态反应形式上传多张图像

时间:2021-04-15 07:46:59

标签: angular api angular11

我想要做的是为单个产品上传多张图片。我无法在任何地方解决这个问题。我可以上传单张图片,但是当我尝试通过添加动态表单控件来发送多张图片时,它不起作用。

下面是我试过的代码..

Add.Component.html

<div>
 <form [formGroup]="form" (ngSubmit)="submitForm()">

 <div class="form-group">
  <input type="file" formControlName="image" (change)="uploadFile($event)">
 </div>

 <div class="form-group >
  <input type="text" formControlName="name">
 </div>

 <div class="form-group">

  <button type="button" (click)="addalternateImage()">Add Alternate Image</button>
  <div formArrayName="alternateImage" *ngFor="let image of alternateImage.controls; let i=index">
    <input [formControlName]="i" (change)="uploadFile($event)" type="file">
  </div>

 </div>

  <div class="form-group">
   <button >Upload</button>
  </div>
  </form>
 </div>

Add.componenet.ts

export class AddComponent implements OnInit {

  name: string | any;
  image: any = [];

 constructor(private service: UploadService, private fb: FormBuilder) {}

 ngOnInit(): void {}

 // Adding alternate image control
 get alternateImage() {
  return this.form.get('alternateImage') as FormArray;
 }
 addalternateImage() {
   this.alternateImage.push(this.fb.control(''));
 }

  form = this.fb.group({
   name: [''],
   alternateImage: this.fb.array([]),
   })

  uploadFile(event: any) {
   this.alternateImage = event.target.files[0];
  }


  submitForm() {
   const formData: any = new FormData();
   formData.append("Name", this.form.controls['name'].value);
   formData.append("Image", this.alternateImage, this.alternateImage.name);

   }
  }

我想要这样发送数据

{
  "name":"productname",
  "image":{ "img1" , "img2" , "img3" }
}

1 个答案:

答案 0 :(得分:0)

我对这个问题的解决方案是保留一个单独的图像数组。图像在数组中的索引等价于它在表单中的索引。

这是假设您一次只使用一种产品。如果您有一个表单,您可以在其中动态添加产品,然后为每个产品添加图像,那么我将使用 2D 数组(图像数组的数组)。

类型脚本:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import {
  FormArray,
  FormBuilder,
  FormGroup,
  Validators,
} from '@angular/forms';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  productImageForm: FormGroup;
  images: any[];

  constructor(private fb: FormBuilder, private http: HttpClient) {
    this.images = [];
    this.productImageForm = this.fb.group({
      productName: ['', Validators.required],
      images: this.fb.array([this.getImageFormGroup()]),
    });
  }

  private getImageFormGroup() {
    // keep place of added image control in images array
    this.images.push(undefined);
    return this.fb.group({
      imagePath: [null, Validators.required],
    });
  }

  get imagesFormArray() {
    return this.productImageForm?.get('images') as FormArray;
  }

  public addImageForm() {
    this.imagesFormArray.push(this.getImageFormGroup());
  }

  public removeImageForm(imageIndex: number): void {
    this.imagesFormArray.removeAt(imageIndex);
    // remove image from image array
    this.images.splice(imageIndex, 1);
  }

  public onFileChange(event: any, index: number): void {
    const file = event.target.files[0];
    // replace image in images array
    this.images.splice(index, 1, file);
    if (!file) {
      this.imagesFormArray.controls[index].get('imagePath')?.patchValue(null);
    }
  }

  public submit(): void {
    // check that product name has been given
    // and that all image inputs have been utilized
    if (this.productImageForm.valid) {
      this.upload();
    } else {
      console.log('Form is not valid');
    }
  }

  private upload() {
    // check for max image size
    this.images.forEach((file) => {
      if (file.size > 10000000) {
        alert('Each File should be less than 10 MB of size.');
        return;
      }
    });

    const images = new FormData();

    this.images.forEach((image,) => {
      images.append('fileData', image);
    });

    this.uploadImages(images)
      .pipe(take(1))
      .subscribe(
        (res) => {
          console.log('success');
        },
        (err) => {
          console.log(err);
        }
      );
  }
    
      private uploadImages(imagesToUpload: FormData): Observable<any> {
        const productName = this.productImageForm.get('productName').value;
        return this.http.post('yourEndpoint/' + productName, imagesToUpload);
      }
    }

HTML:

<div>
  <form [formGroup]="productImageForm">
    <mat-form-field>
      <mat-label>ProductName</mat-label>
      <input matInput type="text" formControlName="productName" />
    </mat-form-field>
    <div formArrayName="images">
      <div
        class="card m-2 p-2"
        *ngFor="let image of imagesFormArray.controls; let i = index"
        [formGroupName]="i"
      >
        <div class="d-flex justify-content-between">
          <input
            type="file"
            formControlName="imagePath"
            (change)="onFileChange($event, i)"
          />
          <button mat-icon-button (click)="removeImageForm(i)">
            <mat-icon>remove</mat-icon>
          </button>
        </div>
      </div>
      <button mat-icon-button (click)="addImageForm()">
        <mat-icon>add</mat-icon>
      </button>
      <button mat-rised-button (click)="submit()">Submit</button>
    </div>
  </form>
</div>

在这个例子中,我使用的是有棱角的材料。 如果您想使用有角度的材料,请不要忘记将必要的导入添加到您的模块中:

模块.TS

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';


import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    FormsModule,
    BrowserAnimationsModule,
    MatFormFieldModule,
    MatInputModule,
    MatIconModule,
    MatButtonModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
相关问题