JQuery Form Plugin File Upload using POST redirects to POST response
Asked Answered
W

5

5

Please help guys, This one is a major BLOCKER!

I have a project that uses NodeJS + jQuery Form Plugin + Typescript in which I am trying to do a file upload. After the file upload the server sends a response to the POST message which renders on the screen. The file does get uploaded successfully and completely before the POST response renders on the screen. I expect the POST response to call the "success" function instead of having the page redirected to show the JSON response.

Here's the code:

$(new ID().setAsRoot().selectId()).append(
    "<form id=\"fileUploadForm\" accept-charset=\"utf-8\" method=\"post\" action=\"/upload\" enctype=\"multipart/form-data\">" +
        "<input id = \"filename\" type=\"file\" name=\"userfile\" multiple=\"multiple\" />" +
        "<button type=\"submit\" id = \"submitButton\"> Upload </button></form>");

var form = $("#fileUploadForm");
form.submit(function (e) {
    //e.preventDefault();
    this.ajaxSubmit({
        type: form.attr('method'),
        url: form.attr('action'),
        data: form.serialize(),
        success: function (data) {
            var x = JSON.parse(data);
            alert("Success : " + x);
        },
        error: function (data) {
            var x = JSON.parse(data);
            alert("Error : " + x);
        }
    });
});

the success function does not get called (which means the alert message doesn't show). The JSON data just gets rendered on the screen like this:

{
  "path": "data\\cb3409f1cc234ec3f64b60d80be13a3e.html",
  "name": "feed.html"
}

There is an error on the console that says:

Uncaught SyntaxError: Unexpected token : shortcut_manager.js:123
(anonymous function) shortcut_manager.js:123
(anonymous function) extensions::messaging:327
Event.dispatchToListener extensions::event_bindings:386
Event.dispatch_ extensions::event_bindings:371
Event.dispatch extensions::event_bindings:392
dispatchOnMessage

Here's the server side code that handles it. The server uses NodeJS formidable module.

public upload(req:express.Request, res) {

        var form = new formidable.IncomingForm();
        var originalFileName:String;
        var filePath:String;
        form.uploadDir = this.directory;
        form.keepExtensions = true;
        form.type = 'multipart';
        var fields = [];
        form
            .on("error", function (err) {
            })
            .on("field", function (field, value) {
            })
            .on("end", function () {
                res.send({
                    path: filePath,
                    name: originalFileName
                });
            })
            .on("file", function (name, file:formidable.File) {
                originalFileName = file.name;
                filePath = file.path;
            });
        form.parse(req);
        return;
    }

--Update--

If I do $.ajax instead of this.ajax. The file does not upload. The browser console shows an error:

XMLHttpRequest cannot load http://localhost/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. 
Wareing answered 22/12, 2013 at 12:55 Comment(10)
Don't you have to add a status code in your response ?Overcome
Added status code to POST response - still won't work - Please see the updated code above. ThanksWareing
Ok, sorry that was just a quick idea. Another one is : using $(this) instead of this in your submit callback. I have the feeling you're accessing the HTML element. Do you get any error in the devloper console by the way ?Overcome
Are you referring to "this" from "this.ajaxSubmit()". That's not a callback. If I replace that with $(this), IDE throws an error: "Argument types dont match parameters". Thanks.Wareing
I am getting an error on the browser console - which I've shown above. On the dev console I get the "Error: Can't set headers after they are sent." as I've mentioned in my question above. Thanks.Wareing
For the node.js error : this post will probably help you #7042840 . I'm not extensively familiar with jquery form plugins, however the browser console tells you that you have a Syntax error. Debug it using the browser console. As for the compilation error, what is your type definition for jquery forms ?Overcome
There's not "type" for the form. Its pure javascript. No typescript here.Wareing
Sounds like the form is submitting normally. Are you getting any errors in the console? Also I would think it would be $.ajax instead of this.ajax.Joppa
Thanks for that suggestion. $.ajax does not load the at all. It shows an error which you may know of. Although your suspicion is right because, when I use "this.ajax" the file does get uploaded but the console shows an error "Type <Object> has no method ajax" for a short span.Wareing
Does the error "Uncaught SyntaxError: Unexpected token..." appear on the browser console? It appears that it has nothing to do with the code that you've shown. Also, what browser are you testing in?Zeralda
U
1

Based on your comment:

"Thanks for that suggestion. $.ajax does not load the at all. It shows an error which you may know of. Although your suspicion is right because, when I use "this.ajax" the file does get uploaded but the console shows an error "Type has no method ajax"

  • You can't upload files using $.ajax() the same way you usually upload your form data.
  • Because of the error when you use this.ajax the form gets submitted. That's why you see the JSON response in the browser.

The question is where does this.ajax come from? Did you copy the code from an example that uses a library you haven't included?

In order to upload files via AJAX you need some kind of plugin (doing it yourself is some effort, especially if you need support for older browsers).

Update

The submit handler should be as follows:

form.submit(function (e) {
  e.preventDefault();
  $(this).ajaxSubmit().done(function (data) {
    var x = JSON.parse(data);
    alert("Success : " + x);
  }).fail(function (data) {
    var x = JSON.parse(data);
    alert("Error : " + x);
  });
});

Explanation: Since you want to call a jQuery plugin you need a jQuery object, hence $(this). ajaxSubmit() does not need any arguments (you can pass in options if you want, though). Because I didn't pass in arguments the callbacks are appended, in this case with doneand fail (instead of success and error).

Ukase answered 27/12, 2013 at 11:15 Comment(4)
Thanks for your comment. I've modified this question and added more details. I'm using JQuery form plugin to upload. Please take another look at the question. I appreciate your help.Wareing
@Wareing There are hundreds of form plugins. Which one do you use? Most of those plugins can't handle file uploads btw.Ukase
@zeroflagL I modified the code as you suggested. Although "$(this)" throws an error so I'm just using "this". The callback functions done and fail are not being called.That aside, the page does not redirect to the JSON response any more - which was the core problem for which I posted this question. So the bounty is all yours. Thanks a lot for your effort.Wareing
@zeroflagL Actually I'm using "form.ajaxSubmit" instead of "this.ajaxSubmit" or "$(this).ajaxSubmit". Using "this" does not upload the file at all.Wareing
N
0
var form = $("#fileUploadForm");     
 $.ajax({
      type:form.attr('method'),
      url:form.attr('action'),
      dataType: 'json', //  Expect a return value of json
      data:form.serialize(),
             success: function(data){
      }});
Nemhauser answered 22/12, 2013 at 12:55 Comment(0)
Q
0

Replace this.ajax("http://..." to url:form.attr('method')

  var form = $("#fileUploadForm");     
  $.ajax({
      type:form.attr('method'),
       url:form.attr('action'),
      data:form.serialize(),
             success: function(data){
      }});
Quickfreeze answered 25/12, 2013 at 17:24 Comment(1)
Thanks, thats a very useful approach and I have changed my code to accordingly - but the outcomes have not changed at all. The exact same thing is still happening. Do you need to know anything from the server side maybe. I've posted some server side code too.Wareing
U
0

Are you asking why am I getting the error:

XMLHttpRequest cannot load localhost/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:8080' is therefore not allowed access.

If so then what you need on your localhost server (assuming that is also Node) is a header set on the response from localhost to allow the Origin of localhost:8080 to access this resource like this:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');

Or perhaps you are actually trying to request from the same server but forgot that 8080 is your test server: if so then in your test you should list your URL as

$.ajax("http://localhost:8080", { //....

or to repeat the current origin:

$.ajax( window.location.origin,{ // ....

Your last alternative to avoiding this (if you can't set the Origin policies on the response) is to use a jsonp service which is less strict but also less featured, but that's not appropriate for your task so I won't go into that.

Either way once you get past the Origin policy you'll have other hurdles as @zeroflagL mentions. Here's a method that might suit you: How to handle cross domain iframe file upload json response?

Untried answered 28/12, 2013 at 1:32 Comment(2)
Thanks for your comment. I've modified this question. I'm using JQuery form plugin to upload. Please take another look. I appreciate your help.Wareing
@EternallyCurious, if you're still getting the access control error then you still need to look at my answer above regardless of how you plan to upload the file.Untried
Z
0

I think there are several different issues with your client-side code.

I see that you define $form but I never see where you define form. You then call form.attr(...). Unless you have defined form somewhere else this will immediately throw an error.

More importantly, standard $.ajax() cannot upload files on older browsers (even as recent as IE 9!) The ability to do an XHR file upload was added in XHR2 (see CanIUse). If you intend for your web app to have compatibility with any down-level browsers you'll need to work around this limitation in some way.

The good news is that there are a variety of plugins that do most of the work for you. If you are using a version of jQuery greater than 1.6 I would recommend looking at the jQuery File Upload Plugin. It uses the new XHR file upload functionality when available and falls back on iFrame Transport in browsers that don't support the new hotness. While the iFrame Transport is simple and clever you don't really need to know anything about it, because the plugin abstracts it away. The plugin is completely free too.

The Basic Plugin will do the dirty work for you and the full featured version even has a built in UI. There's plenty of details on how to implement the server side methods as well. The basic syntax is super simple:

$("#fileUploadForm").fileupload()

If you're looking for something even lighter weight, the iFrame Transport Plugin may be all you need. (It's free as well.) I just implemented it in a project today. It's a single very well documented JS file. It enhances the standard functionality of the $.ajax() function. The key is specifying iframe: true in your list of AJAX options. Your ajax call would probably look something like this:

$.ajax("http://localhost", {
    type: $form.attr('method'),
    url: $form.attr('action'),
    data: $form.serialize(),
    dataType: "JSON",
    iframe: true,
    files: $("#MyFileInputId"),
    success: function (data) {
        alert("Success : " + data);
    },
    error: function (data) {
        alert("Error : " + data);
    }
});

On a side note, if you want to make extra sure the non-AJAX POST doesn't occur, you can add another line to your code:

$form.submit(function (e) {
    e.preventDefault();
    // do stuff
    return false;
}

preventDefault() will cancel the POST, even if an error occurs in the code that follows.

Zeralda answered 28/12, 2013 at 3:30 Comment(2)
Thanks for your comment. I've modified this question because a small part of the problem is solved - and added more details. I'm using JQuery form plugin to upload. Please take another look at the question. I appreciate your help. PS. preventDefault() completely prevents the upload.Wareing
That is the intended result for preventDefault(). Without that line the browser was still uploading the file because the AJAX post threw an error and never reached the return false statement. This allowed the browser to execute the default action (a standard non-AJAX HTML form POST).Zeralda

© 2022 - 2024 — McMap. All rights reserved.