首页 > 解决方案 > 在Angular 8中传递包含文本和图像的FormData时出错

问题描述

我有一个 Angular 表单,我在其中输入一些文本字段和一个图像字段,我将它们与 FormData() 捆绑在一起,然后将它们传递给我的服务。

这是我的 HTML 文件:-

<body>
    <a routerLink="/"><img id="mainLogo" src="../../assets/images/main-logo-resized.PNG" alt="Go to main page"></a>
    <input type="button" id="logoutBtn" (click)="onLogout()" value="Logout">
    <div class="genericForm">
        <form #sellBookForm="ngForm" enctype="multipart/form-data" (ngSubmit)="sellBookForm.valid && onSubmit(sellBookForm)">
            <h1>Tell us about your book</h1>
            <input type="text" #bookName="ngModel" [(ngModel)]="bookService.selectedBook.bookName" name="bookName" placeholder="Name of book" required autofocus [ngClass]="{'invalid-textbox': sellBookForm.submitted && !bookName.valid}">
            <div *ngIf="sellBookForm.submitted && !bookName.valid">
                <label class="validation-message">This field is required!</label>
            </div>
            <br>
            <input type="text" #authorName="ngModel" [(ngModel)]="bookService.selectedBook.authorName" name="authorName" placeholder="Name of author" required [ngClass]="{'invalid-textbox': sellBookForm.submitted && !authorName.valid}">
            <div *ngIf="sellBookForm.submitted && !authorName.valid">
                <label class="validation-message">This field is required!</label>
            </div>
            <br>
            <input type="text" #publisherName="ngModel" [(ngModel)]="bookService.selectedBook.publisherName" name="publisherName" placeholder="Name of publisher" required [ngClass]="{'invalid-textbox': sellBookForm.submitted && !publisherName.valid">
            <div *ngIf="sellBookForm.submitted && !publisherName.valid">
                <label class="validation-message">This field is required!</label>
            </div>
            <br>
            <input type="text" #price="ngModel" [(ngModel)]="bookService.selectedBook.price" name="price" placeholder="Price" required ngClass="{'invalid-textbox': sellBookForm.submitted && !price.valid}">
            <div *ngIf="sellBookForm.submitted && !price.valid">
                <label class="validation-message">This field is required!</label>
            </div>
            <br>
            <input type="file" #bookImg="ngModel" [(ngModel)]="bookService.selectedBook.bookImg" name="bookImg" accept="image/*" id="bookImg" (change)="onFileSelected($event)" required ngClass="{'invalid-textbox': sellBookForm.submitted && !bookImg.valid}">
            <label for="bookImg" id="bookImgLabel"><img src="../../assets/images/upload-image-resized.png" alt="Upload">Upload book image</label>
            <div *ngIf="sellBookForm.submitted && !bookImg.valid">
                <label class="validation-message">This field is required!</label>
            </div>
            <br>
            <input type="submit" value="Sell now!">
        </form>
    </div>
    <a routerLink="/marketplace" class="backToMarketplaceLink">Back to marketplace</a>
</body>

这是我的组件文件:-

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { UserService } from '../shared/user.service';
import { BookService } from '../shared/book.service';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-sell-page',
  templateUrl: './sell-page.component.html',
  styleUrls: ['./sell-page.component.css']
})
export class SellPageComponent implements OnInit {

  // Variable to get the book image file
  bookImg;

  // Boolean variable to show/hide div element is case of successful book submission
  showSuccessMessage: boolean;

  // Error messages in case book submission failed
  serverErrorMessages: string;

  constructor(private userService: UserService, private bookService: BookService, private router: Router) { }

  ngOnInit() {
  }

  onFileSelected(event) {
    this.bookImg = event.target.files[0];
    document.getElementById('bookImgLabel').innerHTML = this.bookImg.name;
  }

  onSubmit(form: NgForm) {
    const formData = new FormData();
    formData.append('bookData', JSON.stringify(form.value));
    formData.append('bookImg', this.bookImg, this.bookImg.name);
    this.bookService.postBook(formData).subscribe(
      res => {
        this.showSuccessMessage = true;
        setTimeout(() => {
          this.showSuccessMessage = false;
        }, 1000);
      },
      err => {
        if (err.status === 422) {
          this.serverErrorMessages = err.error.join('<br/>');
        } else {
          this.serverErrorMessages = 'Oops! Something went wrong. Please try again.';
        }
      }
    );
  }

  onLogout() {
    this.userService.deleteToken();
    this.router.navigateByUrl('/login');
  }

}

我收到一个错误this.bookService.postBook(formData).subscribe():-

Argument of type 'FormData' is not assignable to parameter of type 'Book'.
  Type 'FormData' is missing the following properties from type 'Book': bookName, authorName, publisherName, price, bookImg

这是我的服务文件:-

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Book } from './book.model';
import { environment } from 'src/environments/environment';

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

  selectedBook: Book = {
    bookName: '',
    authorName: '',
    publisherName: '',
    price: 0,
    bookImg: null
  };

  constructor(private http: HttpClient) { }

  // HTTP methods

  postBook(book: Book) {
    return this.http.post(environment.baseUrl + '/sell', book);
  }
}

此服务文件正在使用模型类文件:-

export class Book {
    bookName: string;
    authorName: string;
    publisherName: string;
    price: number;
    bookImg: File;
}

我不明白为什么会出现此错误,因为我已将整个表单值与图像文件一起附加到formData组件文件的变量中。我不能将 FormData() 与模型一起使用来传递信息吗?请帮忙,我是Angular的新手。

标签: angularfile-uploadangular8multipartform-data

解决方案


在 BookService 的 postBook 方法中,您期望 Parameter 类型为 Book Class ,但您在组件中使用 FormData 。有很多方法可以解决这个问题:

  1. 在 postBook 中将参数类型更改为 FormData。
  2. 您可以在服务中使用 selectedBook 字段,因为您在其中绑定了值,除了需要单个 formData 的 img 。

推荐阅读