-2

I'm working on an application where I'm sending data from a form by serializing it and then sending it through AJAX. Everything works perfect but I've got the first headache is that when the form has a field of type FILE for upload any kind of file (should be restricted to images only but this is another topic) to my server-side (Symfony2 controller action) code does not get the image field and therefore can not perform any action on the same.

I've done some research (1,2,3,4 and many more docs found at Google) and in some cases it is said that it's possible and in some instance says it is not, others use the XHR object and then I'm confused and not know where to go from here, here I leave my code to throw him a look and tell me what's wrong and what should I do to make the upload if possible (I think it's):

$.ajax({
    async: false,
    type: "POST",
    cache: false,
    url: '{{ path('update-product', {'id': id}) }}',
    data: $('.smart-form').serializeArray(),
    success: function (data) {
        // here goes a message if all was fine
    }
});

This is the HTML field:

<input type="file" id="product_imageFile_file" name="product[imageFile][file]" class="valid">

Of course my form has enctype="multipart/form-data" and this is the request I got from Symfony2 controller action:

array(4)
   [product_name]: string (10) "Producto-1"
   [active]: string (1) "1"
   [product_description]: string (21) "DescripcionProducto-1"
   [_token]: string (43) "sjcpVT34_9-V7Z2doTZsvZsAewO-0Q5hD-a9C6VPNc4"

And as can see here there is not product[imageFile][file] on the request so something is wrong in my jQuery code, can any give me some help or point me to the right place?

NOTE: Since I'm using PHP and some of it's bundles to handle file upload and then manage the entities I don't know if will be a good practice to use any of the thousands of jQuery plugins to do that, that's the cause I don't mention here and I don't use them at all

Thanks in advance

Community
  • 1
  • 1
ReynierPM
  • 17,594
  • 53
  • 193
  • 363
  • 1
    Yes it's possible but you won't see the file the way you're doing it. Google *dropzone ajax upload*. That plugin works fine for me. – Popnoodles Sep 21 '14 at 02:32
  • Plenty of jQuery plugins that do just that. – Lee Taylor Sep 21 '14 at 02:33
  • @Popnoodles take a look to the note I leave at main post the same for Lee Taylor – ReynierPM Sep 21 '14 at 02:35
  • @ReynierPM I don't understand that sentence. To reiterate, **you won't find the file in the ajax-posted form data**. Pick a plugin and read the instructions fully. – Popnoodles Sep 21 '14 at 02:37
  • @Popnoodles I'm saying that I'm using [this bundle](https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/usage.md) that handle all the upload and entities managment as Symfony2 does, but if you said that it's possible thorugh a plugin then I'll read the docs – ReynierPM Sep 21 '14 at 02:39
  • The bundle looks like it only handles the uploads server-side. You know the simplest way to do it, if you don't want a progress bar, is to post to a hidden iframe. – Popnoodles Sep 21 '14 at 02:43
  • @Popnoodles no, I don't need a progress bar or something I just need that the file is send through AJAX that's what I ask in first and I don't follow you with your latest comment around hidden iframe, could you leave a example? If is possible with some test code? – ReynierPM Sep 21 '14 at 02:45
  • There are plenty of examples online, there's no need for another. Posting to an iframe is not sending via ajax, it just means the page doesn't need reloading. – Popnoodles Sep 21 '14 at 02:46
  • 1
    use FormData() with ajax to give PHP it's usual $_FILES, or catch the POST data and handle it yourself. – dandavis Sep 21 '14 at 03:05

1 Answers1

0

Well, finally and after a lot of research I get it and without any external library as some users suggest here, maybe it's a ugly method but it works for me and does what I want. Here is the code:

function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {
        // Only process image files.
        if (!f.type.match('image.*')) {
            // Display some alert or show the user the file is wrong
            continue;
        }

        var reader = new FileReader();

        // Closure to capture the file information.
        reader.onload = (function (theFile) {
            return function (e) {
                // Render thumbnail.
                var span = document.createElement('span');
                span.innerHTML = ['<img id="product_image" class="thumb" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
                document.getElementById('pImage').insertBefore(span, null);
            };
        })(f);

        // Read in the image file as a data URL.
        reader.readAsDataURL(f);
    }
}

document.getElementById('imageFile_file').addEventListener('change', handleFileSelect, false);

$.ajax({
    async: false,
    url: url, // the URL for process the whole form
    type: 'POST',
    data: $('#formID').serialize() + '&img=' + JSON.stringify($("#product_image").attr('src')),
    cache: false,
    success: function (data)
    {
        if (typeof data.error === 'undefined')
        {
            // Handle success here
        }
        else
        {
            // Handle errors here
        }
    },
    error: function (jqXHR, textStatus, errorThrown)
    {
        // Handle errors here
    },
    complete: function ()
    {
        // STOP LOADING SPINNER
    }
});

Hope helps someone else

ReynierPM
  • 17,594
  • 53
  • 193
  • 363