0

Lately I've been trying to solve an issue with no luck, basically I'm trying to submit a form to the server using AJAX, the form has files, so I'm using the FormData javascript object in JQuery 1.12. The data arrives to the server but in I way I don't know how to format it.

This is my AJAX function:

function saveMenu(id){
    var formElement = document.getElementById("menu-form");
    var formData = new FormData(formElement);
    formData.append('_method', 'PUT');
    $( "#form-wrapper" ).toggleClass( "be-loading-active" );
    $.ajax({
        type: 'PUT',
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        },
        url: "{{url('myUrl')}}",
        data: formData,
        enctype: 'multipart/form-data',
        processData: false,
        success: function(response) {
            toastr.success('Yai! Saved successfully!')
        },
        error: function(response) {
            toastr.error('Oh oh! Something went really wrong!')
        },
        complete: function() {
            $( "#form-wrapper" ).toggleClass( "be-loading-active" )
        }
    });
}

and when I perform a dd($request->all()); in my controller I get something like this:

array:1 [
  "------WebKitFormBoundaryRCIAg1VylATQGx46\r\nContent-Disposition:_form-data;_name" => """
    "_token"\r\n
    \r\n
    jtv4bnn8WQnP3eqmKZV3xWka2YOpnNc1pgrIfk0D\r\n
    ------WebKitFormBoundaryRCIAg1VylATQGx46\r\n
    Content-Disposition: form-data; name="blocks[43][title]"\r\n
    \r\n
...

Things I've tried:

  • Set the HTTP verb to POST. Same result.
  • Set the AJAX contentType: false, contentType: application/json. Empty response.
  • Remove enctype: 'multipart/form-data'. Same response.

Any help is appreciated.

9
  • Hmm.. ill try to make a workable instance in my place. did you try this dd($request->_method)? Commented Aug 4, 2017 at 10:12
  • @RomnickSusa Yes, it returns null. Commented Aug 4, 2017 at 10:15
  • did you remove js cache after removing nctype: 'multipart/form-data because I think it is key Commented Aug 4, 2017 at 10:23
  • @ThomasMoors In my case it looks the same. Commented Aug 4, 2017 at 10:24
  • if you're not using versions of jQuery prior to 1.9.0. , you should change the ` type: 'PUT'` to ` method: 'PUT'` Commented Aug 4, 2017 at 10:26

6 Answers 6

3

This fixed it for me

data: form_data,
contentType: false,
processData: false,

processData: false prevents jQuery from parsing the data and throwing an Illegal Invocation error. JQuery does this when it encounters a file in the form and can not convert it to string (serialize it).

contentType: false prevents ajax sending the content type header. The content type header make Laravel handel the FormData Object as some serialized string.

setting both to false made it work for me. I hope this helps.

$('#my-form').submit(function(e) {
        e.preventDefault();
        var api_token = $('meta[name="api-token"]').attr('content');
        form_data = new FormData(this);
        $.ajax({
            type: 'POST',
            url: '/api/v1/item/add',
            headers: {
                Authorization: 'Bearer ' + api_token
            },
            data: form_data,
            contentType: false,
            processData: false,
            success: function(result,status,xhr) {
                console.log(result);
            },
            error: function(xhr, status, error) {
                console.log(xhr.responseText);
            }
        });
    });

also remember to use $request->all(); $request->input() excludes the files

Sign up to request clarification or add additional context in comments.

Comments

1

I've been trying to debug that for 2 hours and i found out that method PUT is not working with formData properly.

Try changing

type : "PUT" 

into

method : "POST"

Then change your method on your backend from put to post and you'll see the difference. I used below codes to test it

$("#menu-form").submit(function (){
    var fd = new FormData();
    fd.append('section', 'general');
    fd.append('action', 'previewImg');
    fd.append('new_image', $('.new_image')[0].files[0]); 
    $.ajax({
        method : 'POST',
        headers: {
            'X-CSRF-TOKEN': '{{ csrf_token()}}'
        },
        url: "{{url('upload-now')}}",
        data : fd,
        contentType: false,
        processData: false,
        success: function(response) {
            console.log(response);
        },
    });
    return false;
});

And in my controller

public function test(Request $request){
    dd($request->all());
}

Ill try to research more about this issue.

3 Comments

Sorry but my form is more complex than just 3 inputs you can comfortably append, it has multiple levels and more files. Anyway I've tried to change to the POST method as I said in the question and it didn't changed for me.
I'll revise my answer later
I have a solution, but I discarted jquery ajax function in favor of XMLRequest()
1

Laravel 7, if use method PUT in ajax, you can follow 1. change method method: 'PUT' to method: 'POST' 2. add formdata.append with _method PUT like this example :

$('#updateBtn').click(function(e){
    e.preventDefault();
    var frm = $('#tambahForm');
    frm.trigger("reset");
    $('.edit_errorNama_kategori').hide();
    $('.edit_errorGambar').hide();
    var url = "/pengurus/category/"+$('#edit_id').val();
    var formdata = new FormData($("#editForm")[0]);
    formdata.append('_method', 'PUT');  //*** here

    $.ajax({                       
        method :'POST', //*** here
        url : url,
        data : formdata,
        dataType : 'json',
        processData: false,
        contentType: false,
        success:function(data){
          if (data.errors) {
            if (data.errors.nama_kategori) {
                $('.edit_errorNama_kategori').show();
                $('.edit_errorNama_kategori').text(data.errors.nama_kategori);
            }
            if (data.errors.gambar){
              $('.edit_errorGambar').show();
              $('.edit_errorGambar').text(data.errors.gambar);
            }
          }else {
            frm.trigger('reset');
            $('#editModal').modal('hide');
            swal('Success!','Data Updated Successfully','success');
            table.ajax.reload(null,false);
          }
        },
        error: function (jqXHR, textStatus, errorThrown) {
          alert('Please Reload to read Ajax');
          console.log("ERROR : ", e);
        }
    });
});

its works for me

Comments

0

Finally I gave up trying to make it work and tried a more vanilla approach, I still don't know the reason why the request is formated like that, but the XMLHttpRequest() function works perfectly and the migration is not a big deal.

The equivalent of the function I posted about would be:

function saveMenu(action){
    var formElement = document.getElementById("menu-form");
    var formData = new FormData(formElement);
    formData.append('_token', $('meta[name="csrf-token"]').attr('content'));

    var request = new XMLHttpRequest();
    request.open("POST", "{{url('myUrl')}}");
    request.send(formData);

    request.onload = function(oEvent) {
      if (request.status == 200) {
        toastr.success('Yai! Saved successfully!');
      } else {
        toastr.error('Oh oh! Something went really wrong!');
      }
      $( "#form-wrapper" ).toggleClass( "be-loading-active" );
    };
}

Comments

0

Bit late, but; This will solve your problem;

var formData = new FormData(document.getElementById('form'));
console.log(...formData);

var object = {};
formData.forEach(function (value, key) {
    object[key] = value;
});

Then you can send this object to the server. This is much more readable and works great.

OR

You can simply send this directly;

JSON.stringify(Object.fromEntries(formData));

This is the newer approach. And don't give up :-)

Comments

0

if you are getting responses like this

Array ( [------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition:_form-data;_name] => "mencommentid" 43 ------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition: form-data; name="mmencommentid" 39 ------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition: form-data; name="replymencomment" asd ------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition: form-data; name="video" ------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition: form-data; name="file"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundaryZHCPkXfouoiFpLDg Content-Disposition: form-data; name="audio"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundaryZHCPkXfouoiFpLDg-- )

then

cache: false,
processData: false,
contentType: false,

adding these inside request helps me

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.