How to angular2 post JSON data and files In same request

18,007

Solution 1

So I've been trying to do that too, and for something which look really simple I ended up with a lot of trouble to figure out a solution. Hopefully some coworkers helped me and we came up with something reasonable.

This documentation helped us a lot: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects

And here's the Angular code:

class SomeService {
  someMethod(fileToUpload: File, name: string, version: string) {
    const formData: FormData = new FormData();
    formData.append('file', fileToUpload, fileToUpload.name);

    const overrides = {
      name,
      version,
    };

    const blobOverrides = new Blob([JSON.stringify(overrides)], {
      type: 'application/json',
    });

    formData.append('overrides', blobOverrides);

    const req = new HttpRequest('POST', `some-url`, formData);

    return this.http.request(req);
  }
}

As @Supamiu said, using Blob was the key, and here's an example how to do that.

Solution 2

The below client and service code works fine in my solution, check if this helps

Client Side Code:

    AddModelData(modelData: ModelData, file: any): Observable<any> 
    {
      let urlPath = 'api/SampleActionMethod/AddModelData';
      const mData = JSON.stringify(modelData);
      const formData = new FormData();
      formData.append('data', mData);
      if (file) {
        formData.append('file', file, file.name);
      }
      return this._http.post(this.settings.apiEndPoint + urlPath, formData);
    }

Service Side Code:

public IActionResult PostMethod(IFormFile file)
{      
  try
  {                
    var modelData = JsonConvert.DeserializeObject<ModelData>(Request.Form["data"]); 
    //data is the key that is being passed from client side
    //file in params will have the posted file

    //Do Something with data and file......

    return Ok();
  }
  catch (Exception e)
  {
    return StatusCode(500, e.Message);
  }
}

Solution 3

//app.component.html

<input type="file" name="file" (change)="onChange($event)">
<button (click)="onSubmisson()" [disabled]="file==null" >Submit</button>

//app.component.ts

file:File = null;

onChange(event){
 this.file = event.target.files[0]
}

onSubmisson(){
 this._auth.uploadFileAndData(this.file).subscribe(
 res => {
    console.log(res);
 },err => {
    console.log(err);
 });
}

//upload.service.ts

uploadFileAndData(file){
  var test = {test:"test"}
  const formData = new FormData();
  formData.append('data', JSON.stringify(test));
  formData.append('file', file, file.name);
  return this._http.post<any>(this._uploadurl, formData);
}

//node server

var multer = require('multer');
var path = require('path');

var storage = multer.diskStorage({
  // destination
  destination: function (req, file, cb) {
    cb(null, './uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  }
});

var upload = multer({ storage: storage }).array("file", 12);

router.post("/upload",  function(req , res){
    upload(req, res, function (err) {
        if(err){
            console.log(err);
        }else{
            console.log(req.body);
            console.log('files', req.files);
        }
    })
    res.status(200).send({});
});

// output

{ data: '{"test":"test"}' }

files [ { fieldname: 'file',
    originalname: 'acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    encoding: '7bit',
    mimetype: 'image/jpeg',
    destination: './uploads/',
    filename: 'acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    path: 'uploads\\acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    size: 49647 } ]

Solution 4

The way my manager @Jesse come up with is like:

public uploadFiles(id: ServerID, brd: File, sch: File, args: any[]): Observable<Blob> {
        const data = new FormData();
        data.append('brd', brd);
        data.append('sch', sch);
        data.append('data', JSON.stringify(args));
        return this.httpClient.post(URL, data, {
            responseType: 'blob',
        });
    }

The definition of the FormData append() is append(name: string, value: string | Blob, fileName?: string): void; which allows you to append JSON parameters to it or upload a file.

Share:
18,007
Kery Hu
Author by

Kery Hu

love java ,spring boot ,spring cloud and docker ,and on the way always! love Maths , Big data ,machine learning

Updated on June 29, 2022

Comments

  • Kery Hu
    Kery Hu almost 2 years

    I want to implement post file and Json data in the same request .

    below is the upload file code :

    upload(url:string,file:File):Observable<{complate:number,progress?:number,data?:Object}>{
    
    
        return Observable.create(observer => {
          const formData:FormData = new FormData(),
            xhr:XMLHttpRequest = new XMLHttpRequest();
          formData.append('uploadfile', file);
    
    
          formData.append("_csrf", this.tokenService.getCsrf());
          xhr.open('POST',url, true);
          xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
              if (xhr.status === 200) {
                observer.next({complate:1,progress:100,data:JSON.parse(xhr.response)});
                observer.complete();
              } else {
                observer.error(xhr.response);
              }
            }
          };
    
          xhr.upload.onprogress = (event) => {
            observer.next({complate:0,progress:Math.round(event.loaded / event.total * 100)});
          };
    
    
          const headers=new Headers();
          let token: string = localStorage.getItem('access-token');
          xhr.setRequestHeader('Authorization', `Bearer ${token}`);
          xhr.send(formData);
        }).share();
    

    How to integration with angular2 http.post(url, JSON.stringify(data)).

  • Brian Ogden
    Brian Ogden over 6 years
    Hi @Maxime how are you supposed to parse the JSON data on the backend?
  • maxime1992
    maxime1992 over 6 years
    Sorry about that Brian but I was not in charge of that and not even working in this company anymore. Wishing you luck
  • Brian Ogden
    Brian Ogden over 6 years
    No worries thanks @Maxime for the frontend answer :)
  • Ahadu Melesse
    Ahadu Melesse almost 4 years
    Great Solution. One think I noticed, we don't need the IFormFile payload at the API level, the values can be retrieved from the HttpRequest.