0

Right now I have multiple forms on a page that I want to be rid of. So currently I'm doing this.

JAVASCRIPT

  $("button[id$='uploadfile']").click(function (evt) {
        //////////////////////////////////////////////////////
        // This code block works
        alert("upload file");
        var file1 = $('#csvIdentifierFileBase').val();
        var formData = new FormData();
        var opmlFile = $('#csvIdentifierFileBase')[0];
        formData.append("opmlFile", opmlFile.files[0]);
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'alt/Import');
        xhr.send(formData);
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                alert(xhr.responseText);
            }
        };
        //////////////////////////////////////////////////////

        //////////////////////////////////////////////////////
        // This code block does not
        $.ajax({
            type: 'POST',
            url: 'alt/Import',
            data: formData,
            enctype: 'multipart/form-data',
            //cache: false,
            //contentType: false,
            //processData: false,
            success: function (result) {
                alert(result.success);
            },
            error: function (a, b, c) {
                alert("An error has occurred.");
            }
        });

HTML

        <div class="col-md-12">
            <input type="file" name="csvIdentifierFileBase" id="csvIdentifierFileBase"/>
            <button id="uploadfile" name="action" value="Import" >Import</button>
        </div>

CONTROLLER

    [System.Web.Http.HttpPost]
    public ActionResult Import()//HttpPostedFileBase csvIdentifierFileBase)
    {
        HttpResponseMessage result = null;
        HttpPostedFileBase file = Request.Files[0]; //Uploaded file
    }

Not changing anything besides the javscript call to this controller method, and using the XmlHttpRequest it works fine, is there a way to switch to a jquery/ajax style call so I'm not relying on the XmlHttpRequest object and still have it call into the controller? I'm looking for a native solution and not another type of plugin... is that possible? also can't wrap the input and button in a AJAX.BeginForm tag as I'm trying to eliminate the number of forms on one page.

DRobertE
  • 3,478
  • 3
  • 26
  • 43
  • I have just posted the answer http://stackoverflow.com/questions/23007332/how-to-upload-file-via-mvc4-and-get-json-response/23008287#23008287 also see this http://stackoverflow.com/questions/19042116/ajax-beginform-in-mvc-to-upload-files/19044689#19044689 – Ashwini Verma Apr 11 '14 at 13:39
  • I can't use the Ajax.beginform as I would then end up with a form within a form and that doesn't work. That is why I'm doing the above without a form tag. I need to be able to do what you did Ashwini on that post only without the form tags. – DRobertE Apr 11 '14 at 14:16

1 Answers1

1

Hopefully this will help someone else out there as I spent quite some time on this. Here is how to post a file via $.ajax WITHOUT any additional plugin, and WITHOUT an Ajax.BeginForm tag in the html view.

JAVASCRIPT

    $("button[id$='uploadfile']").click(function (evt) {
    alert("upload file");
    // relatively irrelevant name used here but is not what model binder uses in MVC
    var file_data = $("#csvIdentifierFileBase").prop("files")[0];   // Getting the properties of file from file field
    var form_data = new FormData();                  // Creating object of FormData class
    // THIS IS IMPORTANT, THE NAME HERE **"file"** IS WHAT THE MODEL BINDER USES IN MVC CONTROLLER
    form_data.append("file", file_data);            // Appending parameter named file with properties of file_field to form_data
    //form_data.append("user_id", 123);             // Adding extra parameters to form_data
    $.ajax({
        url: "alt/Import",
        dataType: 'script',
        cache: false,
        contentType: false,
        processData: false,
        data: form_data,                            // Setting the data attribute of ajax with file_data
        type: 'post'
    });
});

HTML NO FORM TAGS NO PLUGGINS

         // name and id of input type file relatively irrelevant 
        <div class="col-md-12">
            <input type="file" name="csvIdentifierFileBase" id="csvIdentifierFileBase"/>
            <button id="uploadfile" name="action" value="Import" >Import</button>
        </div>

CONTROLLER

    [System.Web.Http.HttpPost]
    public ActionResult Import(HttpPostedFileBase file) // THIS VAIRABLE NAME HAS TO BE THE SAME AS WHAT IS PASSED IN VIA THE SCRIPT FOR FORM DATA
    {
        HttpResponseMessage result = null;
        HttpPostedFileBase file = Request.Files[0]; //Uploaded file JUST A SECOND WAY TO ACCESS THE SAME INFORMATION THAT IS COMING IN AS HttpPostedFileBase file
    }

HOWEVER here's the GIT FormData() is not supported in IE so this approach will not work for IE

Supporting information can be found here http://blog.w3villa.com/websites/uploading-filesimage-with-ajax-jquery-without-submitting-a-form/

IE ALTERNATIVE TO ABOVE

HTML

        <div class="col-md-12">
            <input type="file" name="csvIdentifierFileBase" id="csvIdentifierFileBase"/>
            <button id="uploadfile" name="action" value="Import" >Import</button>
        </div>

JAVASCRIPT

$("button[id$='uploadfile']").click(function (evt) {
    evt.preventDefault();
    var $newForm = $('<form>', {
        'action': 'alt/Import',
        'method': 'post',
        'enctype': 'multipart/form-data',
        'target':'_top'
//dynamically appending the input type file to the dynamically generated form and it MUST be appended to the page to work. "appendTo(body") submit then remove
 }).append($("#csvIdentifierFileBase")).appendTo('body').submit().remove();

});

NOW THE NAME DOES MATTER

Since the input element is being dynamically added to the form the name does have to match the controller method param name for the model binder to work.

[System.Web.Http.HttpPost]
public ActionResult Import(HttpPostedFileBase csvIdentifierFileBase)
{

}

Fundamentally no different then having a form tag around the inputs which is the situation I'm trying to avoid. The reason I'm doing it this way and why I was trying to avoid multiple forms on a page was because I was in a situation where I would have had nested form tags which will not work.

DRobertE
  • 3,478
  • 3
  • 26
  • 43
  • This is perfect! This exactly what I was looking for! I too didn't want to use plugins or more forms than necessary. Thanks so much for posting this. – GarudaLead Sep 18 '14 at 14:21