Posting a form with file attachments using pjax (and jQuery.form?)
Asked Answered
C

4

7

I successfully use pjax for links and forms (GET as well as POST). But now I have a form which also has to send an <input type="file"...>. Since pjax does not support this, I had a look at https://github.com/malsup/form (jquery.form plugin) which does support submitting form data with files, but not in the "pjax" way of working with browser history objects.

So, how would it be possible to use pjax functionality with forms that contain file fields? Any ideas?

Edit: The reason why I do not simply use FormData objects, but the jquery.form plugin: Internet Explorer can not handle them. And the plugin has a workaround for this browser. I do not insist of using jquery.form plugin, but I need a way to make it work with all the major browsers.

Collinear answered 17/12, 2012 at 14:21 Comment(2)
You can try to convert the data to Base64String with JS and post it as a file and then in the post you can convert it to byte array and save the file with the array.Langrage
IE<9 do not support FILE api, you can convert data pjax collecting to form and post it with iframe which contains the file input.Kestrel
S
5

It seems like you may need to use a FormData object in your AJAX/pJAX request which can process files. You can read more on the Mozilla Developer Network.

For example, if this is your form:

<form enctype="multipart/form-data">
<input name="file" type="file" />
<input type="button" value="Upload" />
</form>

First get the file contents like so:

var formData = new FormData($('form')[0]);

Then you could use a jQuery $.ajax request or a simple XMLHttpRequest(); like so:

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://foo.com/processfile.php");
xhr.send(formData);

Or similarly in jQuery:

$.ajax({
    url: 'http://foo.com/processfile.php',
    type: 'POST',
    data: formData,
    cache: false,
    contentType: false,
    processData: false
});

On the server side, in processfile.php, you can receive/display the file contents with:

$file = $_FILES['file']['name'];

This should work with pJAX as it is asynchronous! Just make sure you place this request BEFORE your pJAX request, or if you're using jQuery, you can add it as part of the success callback. For example (without knowing which pJAX library you are using):

$.ajax({
    url: 'http://foo.com/processfile.php',
    type: 'POST',
    data: formData,
    cache: false,
    contentType: false,
    processData: false,
    success: function(data) {
       $.pjax({url: url, container: '#pjax-container'});
    }
});

Edit: If you would like to support IE7+, you need to fallback to using a hidden iframe element for the upload as FormData is only supported in Internet Explorer 10. A great plugin for submitting files which I have tested and works without jQuery is http://fineuploader.com/ which in my opinion is better/easier to use than the https://github.com/malsup/form (jquery.form plugin).

Salade answered 19/12, 2012 at 16:6 Comment(7)
jasdeepkhalsa, thank you for your elaborate response! But unfortunately it did not solve my problem since that browser (MSIE) is unable to work with FormData objects. That is why I tried to work with the jquery.form plugin. It has a workaround with some iframe magic.Collinear
@Collinear - I see, thanks for clarifying. I think the plugin which I've posted should solve your problem!Salade
Unfortunately I am unable to find a way to integrate FineUploader, jQuery.form or Uploadify into pjax. I would need a way to tell pjax to handle the form correctly if it has file input fields. Doing two separate HTTP requests is not really an option, since my server script sends back either the form (when an error occured) or some other success page. (I hope I'm not confusing you...)Collinear
@Collinear - Firstly, I think you've not stated your problem clearly at all - please state clearly in your question (a) what your code currently looks like client-side and server-side (b) which pjax solution you are currently using (c) exactly what data your server is sending back and fourth. Secondly, pushState is not supported until Internet Explorer 10, so I don't know how you were hoping to achieve "integration" with pjax in IE?Salade
Ok. I am using github.com/defunkt/jquery-pjax and submit all my forms with $.pjax.submit. I just want to use exactly this behaviour also for forms containing file input fields. Sorry if I was not clear here.Collinear
although I still have no solution for my problem, the time ran out, so I had to decided who to give the bounty. Thank you for your efforts. They are really appreciated. And thank you to Faraz, Dasun and Dean as well.Collinear
@Collinear - Thanks for awarding in spite of you not receiving a satisfactory answer. I'm still unsure of your exact problem. I understand you also want to use the pjax behaviour for submitting files - but did you want this to work also in IE with the hidden iframe element? Why is it that you could not use the plugins mentioned? Can you also post your server-side script so we can see EXACTLY what we're working with please?Salade
P
1

jQuery Ajax code

jQuery('document').ready(function(){

    var input = document.getElementById("imagefile");
    var formdata = false;
    if (window.FormData) {
        formdata = new FormData();
    }

    input.addEventListener("change", function (evt) {

        var i = 0, len = this.files.length, img, reader, file;

        for ( ; i < len; i++ ) {
            file = this.files[i];

            //validation to check whether uploaded files are images
            if (!!file.type.match(/image.*/)) {
                if ( window.FileReader ) {
                    reader = new FileReader();
                    reader.onloadend = function (e) { 
                    };
                    reader.readAsDataURL(file);
                }


                if (formdata) {
                    //send the ajax query to upload the file(s)
                    jQuery.ajax({
                        url: "upload.php",
                        type: "POST",
                        data: formdata,
                        processData: false,
                        contentType: false,
                        success: function (result) {
                            jQuery('div#response').html("Successfully uploaded").fadeOut();
                        }
                    });
                }
            }
            else
            {
                alert('Not a vaild image!');
            }   
        }

    }, false);


});

HTML Code

<form enctype="multipart/form-data">
<input id="imagefile" type="file" name="image" accept="image/*"/ />
</form>

What above code will do for you is, once you upload the file(s) it will 1st of validate the type of the image and upload it via ajax for you. You can do multiple file uploads if you need. If you ever wonder what FormData does,

The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. Its primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form's submit() method would use to send the data if the form's encoding type were set to "multipart/form-data".

What addEventListener does for you is,

addEventListener() registers a single event listener on a single target. The event target may be a single element in a document, the document itself, a window, or an XMLHttpRequest.

You can use upload.php to upload the file(s) at the server level.

If you want to have the this functionality in a plugin you can extend the plugin with the above code and it will not brick your plugin because this is a very straight forward code snippet which gets the job done. I have successfully integrated the code to a plugin with no issues at all.

If you have any issues let me know.

Passifloraceous answered 21/12, 2012 at 2:2 Comment(2)
Hm. I don't see any pjax-y behaviour here. I want pjax and the file upload be joined together in just one call. I really do not want to save some stuff temporarily etc. Just one form and one pjax-y submit. Just like in any other pjax form.Collinear
According to my knowledge Ajax file uploads are not possible but with the use of the above method you can get it done.Passifloraceous
L
0

You can use uploadify seprately for the file upload and in its callback function update the form with uploaded file path or simply set the upload status to true or false and when you submit the form you can access the file from the uploadify temp folder and base your response according to that.

Litharge answered 20/12, 2012 at 10:19 Comment(1)
Yes, I know. But I want pjax and the file upload be joined together in just one call. I really do not want to save some stuff temporarily etc. Just one form and one pjax-y submit. Just like in any other pjax form.Collinear
B
0

One way of doing this is that when you find there is a file upload in the form, construct a hidden iframe on the page, along with the entire form in it, then submit the form in the iframe. Also you need to add a listener on the 'load' event to the iframe, so when the submit returns, you can handle the response. This is how EXT handles such situation.

Betsey answered 25/12, 2012 at 10:7 Comment(2)
You make me curious. What is EXT?Collinear
sencha.com/products/extjs It's a javascript framework, and I think it was kinda hot several years ago.Betsey

© 2022 - 2024 — McMap. All rights reserved.