Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 post-request with a multipart form doesn't include the attached file of the object posted

I'm trying to send a form along with a file to my API through Angular 6, but the post doesn't include the file, even though the object that's supposed to be sent does.

When I'm looking at the console logs I see what is expected, amount:"amount", invoicefile: File.... But In the outgoing request the field shows invoicefile:{}, and now file is received on the other side. Some pictures are included at the end.

Lastly my API is telling my all fields are missing, but I think that another problem.

The component looks like this:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { first } from 'rxjs/operators';
import { FormGroup, FormBuilder, FormControl, Validators, FormArray, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';

import { AlertService } from '../_services';
import { InvoiceService } from '../_services';
import { Invoice } from '../_models';

@Component({
  selector: 'app-registerinvoice',
  templateUrl: './registerinvoice.component.html',
  styleUrls: ['./registerinvoice.component.css']
})
export class RegisterinvoiceComponent implements OnInit {
  public registerForm: FormGroup;
  public submitted: boolean;

  constructor(
    private router: Router,
    private invoiceService: InvoiceService,
    private alertService: AlertService,
    private http: HttpClient,

  ) { }
  fileToUpload: File = null;

  ngOnInit() {
    this.registerForm = new FormGroup({
      serial: new FormControl('', [<any>Validators.required, <any>Validators.minLength(5)]),
      amount: new FormControl('', [<any>Validators.required, <any>Validators.minLength(4)]),
      debtor: new FormControl('', [<any>Validators.required, <any>Validators.minLength(10)]),
      dateout: new FormControl('', [<any>Validators.required, <any>Validators.minLength(8)]),
      expiration: new FormControl('', [<any>Validators.required, <any>Validators.minLength(8)]),
    });
  }
  handleFileInput(files: FileList){
    this.fileToUpload=files.item(0);
  }

  deliverForm(invoice: Invoice, isValid) {
    this.submitted=true;
    if (!isValid){
      return;
    }
    invoice.invoicefile=this.fileToUpload;
    console.log(invoice);
    console.log(typeof(invoice.invoicefile));
    this.invoiceService.create(invoice)
      .pipe(first())
      .subscribe(
        data => {
          this.alertService.success('Invoice successfully uploaded', true);
          this.router.navigate(['/profile']);
        },
        error => {
          this.alertService.error(error);
        });
  }

}

Followed by the service that provides the post:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Http } from '@angular/http';
import { Invoice } from '../_models';
import { FormGroup } from '@angular/forms';

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Content-Type": "multipart/form-data" })
}
@Injectable({
  providedIn: 'root'
})
export class InvoiceService {

  constructor(
    private http: HttpClient
  ) { }
  create(invoice: Invoice){
    return this.http.post('/api/v1/invoices/', invoice, HttpUploadOptions)
  }
}

And lastly the class:

export class Invoice {
    id: any;
    serial: any;
    amount: any;
    debtor: any;
    dateout: any;
    expiration: any;
    fid: any;
    invoicefile: File;
}

The console log that looks correct:enter image description here

And the outgoing request where the file is missing: enter image description here

EDIT:

Now the service code for create looks like this:

create(invoice: Invoice){
    let payload=new FormData();
    payload.append('amount', invoice.amount);
    payload.append('debtor', invoice.debtor);
    payload.append('serial', invoice.serial);
    payload.append('dateout', invoice.dateout);
    payload.append('expiration', invoice.expiration);
    payload.append('invoicefile', invoice.invoicefile);
    return this.http.post('/api/v1/invoices/', payload, HttpUploadOptions)
  }

And the response looks like this. Looks weird to me, and I'm still getting some errors from my back-end, but that's another question. enter image description here

like image 912
Marcus Grass Avatar asked May 28 '18 19:05

Marcus Grass


3 Answers

Your POST request body is actually JSON, not Multipart as you would hope (despite what the Content-Type header says).

In order to remedy that, you need to build a FormData object, and use that in your request instead:

let input = new FormData();
// Add your values in here
input.append('id', invoice.id);
input.append('invoiceFile', invoice.invoiceFile);
// etc, etc

this.http.post('/api/v1/invoices/', input, HttpUploadOptions)
like image 58
user184994 Avatar answered Oct 17 '22 19:10

user184994


Remove the multipart/form-data from the headers to fix this issue

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Content-Type": "multipart/form-data" })
}

Solution

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Accept": "application/json" })
}
like image 26
user2617449 Avatar answered Oct 17 '22 21:10

user2617449


I had previously this one which was giving error

const formData = new FormData();
formData.append(...);
this.http.post(apiUrl, {formData});

I just removed the object from braces and it worked

this.http.post(apiUrl, formData);
like image 3
AbdulRehman Avatar answered Oct 17 '22 20:10

AbdulRehman