3

I am developping a form with some basic inputs and a mini form (in a popup) with a list of foos and each foo have its own attachement file

{

    // form fields
    ...

    foos: [
        {
            // foo form fields
            ...

            attachment: { /* File type */ }
        },
        ...
    ]
}

before i add the attachement property (file upload), everything work good when i submit the whole form with axios to the backend api server (i am using redux-form to manage the form state)

I use JSON.stringify(formValues) to send data with axios as json

But when i add the attachement property i don't know how to send the form because i read that with the file involved in the form i can't no longer send the form as json but I have to use FormData

The problem is I have nested file objects within a list so how can i send the whole form ?

Hayi
  • 6,972
  • 26
  • 80
  • 139

3 Answers3

3

I achieved the same as this.

let formData = new FormData();

formData.append("file", file);

//here my formData is in JSON format
formData.append("formData", JSON.stringify(formData));

const config = {
    method: "POST", //change according to your API
    data: formData,
    url: api, //API Url
    headers: {
      "Content-Type": "multipart/form-data",
    }
  };

axios
  .request(config)
  .then(function(response) {
      console.log(response.data);
    }
  })
  .catch(error => {
    console.log(error);
  });
Sameer Reza Khan
  • 474
  • 4
  • 15
  • i have file nested in a list you solution doesn't work and the content-type in the header must not be motioned – Hayi Sep 19 '19 at 12:02
  • In my case, the file is stored in state, separate from form-data, so if you try with separate list of files and form data then it should work. I don't know how JSON.stringify() will work on files. – Sameer Reza Khan Sep 19 '19 at 12:12
  • It's not my case @SameerRezaKhan if you look at my question they are not separated – Hayi Sep 19 '19 at 12:17
  • I tried this `file = new File(['foo','baar'], 'foobar.txt'); console.log(JSON.stringify(file));` and it gave me an empty object. and it yielded this `{ }`, but when i just wrote `console.log(file)` i saw all the file's properties. – Sameer Reza Khan Sep 19 '19 at 12:19
  • So keep them in a separate list with id's of foos, this is what I think you can do. – Sameer Reza Khan Sep 19 '19 at 12:20
  • the foo are not created yet in the database to have an id – Hayi Sep 19 '19 at 12:21
  • There must be something unique for each foo which will give you id in your backend. You can use that to name your attachment or can append that with the file name. Anyway you will store them only after you have an id for a foo, right? – Sameer Reza Khan Sep 19 '19 at 12:24
  • 1
    I am looking for a solution that not separate file and other properties – Hayi Sep 19 '19 at 12:29
0
  1. Declare a state variable Images which is an array type.
  2. On change of file input assign files to Images array (handleOptionImages()).
  3. Append this Images array in the formData object along with other form data.
  4. Finally, send the formData object in your axios request.

    <form>
    <input type="file" onChange={e =>this.handleOptionImages(e)}>
    <input type="file" onChange={e =>this.handleOptionImages(e)}>
    <input type="text" name="user" value={this.state.value} onChange={e=>this.handleChange(e)}>
    <button onClick={e=>submitForm(e)}>submit</button>
    </form>
    

    define a constructor with blank state like

    constructor(props) { super(props); this.state = { user:"", Images:[] } }

      handleChange = e => {
        this.setState({ [e.target.name]: e.target.value });
      };
    
      handleOptionImages(e) {
        let Images = this.state.Images.slice();
        let media = e.target.files[0];
        Images[] = media; // Update it with the modified email.
        this.setState({ Images: Images });
      }
      submitForm(e){
        let formdata = new FormData();
        formdata.append("user",this.state.user);
        if (this.state.Images) {
          for (const file of this.state.Images) {
              formdata.append("Images[]", file);
            }
        }
    
      // add your axios code 
      axios.post("your api path", formdata)
        .then(res => {
            //handle success
          } else {
            // handle error
          }
        });
      }
    

Please have a look I hope it will help you. Thanks

Sanat Gupta
  • 1,086
  • 1
  • 10
  • 16
0

To set a content-type you need to pass a file-like object. You can create one using a Blob.

const obj = {
  hello: "world"
};
const json = JSON.stringify(obj);
const blob = new Blob([json], {
  type: 'application/json'
});
const data = new FormData();
data.append("document", blob);
axios({
  method: 'post',
  url: '/sample',
  data: data,
})

jQuery + Ajax for more details refer link

$("form#data").submit(function(e) {
    e.preventDefault();    
    var formData = new FormData(this);

$.ajax({
    url: window.location.pathname,
    type: 'POST',
    data: formData,
    success: function (data) {
        alert(data)
    },
    cache: false,
    contentType: false,
    processData: false
});
});
Jaisa Ram
  • 1,687
  • 14
  • 21