3

I'm trying to implement XHR level 2 (file API upload) using Drupal 7's JQuery $.ajax implementation. I've got the feeling I'm almost there.

First of all, I got XHR.send() working according to orginal example on HTML5 demos. But now, I want to use Drupal 7's built in ajax framework.

I found some examples how do this with JQuery but I can't get it working for Drupal 7 with a custom ajax responce. I also found a related (D8) discussion about this on drupal.org.

Here's the code, which returns a ajax error "Illegal invocation". Probably because formData is not in a proper format?

    // 'files' below is a correct object with at least one file

    var file = files[0];
    var formData = new FormData();

    formData.append('file', files[0]);

    // element_settings: see ajax.js in drupal
    var element_settings = {};

    element_settings.progress = { 'type': 'none' }; 
    element_settings.url = '/mymodule/save/ajax';
    element_settings.data = file;
    element_settings.cache = false; 
    element_settings.contentType = file.type;
    element_settings.processData = false;
    element_settings.submit = {
      'savedata': formData
    };

    element_settings.xhr = function() {
      myXhr = $.ajaxSettings.xhr();
      if (myXhr.upload) {
        myXhr.upload.addEventListener('progress', progressHandlerFunction, false);
      } else {
        console.log("Upload progress is not supported.");
      }
      return myXhr;
    };


    var base = '#myelement';
    ajax = new Drupal.ajax(base, $('#myelement'), element_settings); 
    ajax.eventResponse($(ajax.element));

On the server site, I'm using a menu hook with ajax_deliver as delivery callback. This works, but I can't access $_FILES in the same way which is possible if you use xhr.send().

By, the way, I'm aware this only works in modern browsers. I'm using Chrome.

6
  • Does jQuery's $.ajax even know how to send a FormData? If it doesn't, neither will Drupal's Drupal.ajax...
    – Rudie
    Dec 25, 2012 at 0:12
  • Yes, if options.processData = false and options.data = FormData.
    – Rudie
    Dec 25, 2012 at 0:28
  • Yes, that is one of the workarounds mentioned in the links (under "examples") in the description.
    – askibinski
    Dec 25, 2012 at 12:52
  • I didn't read all that =) I was just thinking out loud. The problem won't be to make jQuery do what you want. The problem will be making Drupal.ajax and its messed up pageState 'system' do what you want. I've tried this once too. You should inspect a normal 'ajax' file upload. You'll give up soon enough ;)
    – Rudie
    Dec 25, 2012 at 22:51
  • Yes, I suspect it might be impossible to do this unless you do some serious hacking in Ajax.js and ajax.inc.
    – askibinski
    Dec 26, 2012 at 11:11

1 Answer 1

3

I think your approach is flawed. You should use as much of Drupal's ajax system as possible, even though is wildly uncomprehensible and weird. Don't create your own Drupal.ajax object. Let Drupal handle that and the events and triggers that come with that.

Then there are only 2 problems left:

  1. Don't create an iframe and a fake form and submit that. Use Ajax.
  2. Don't serialize and preprocess that request. Use only what I'm giving you.

They're combined in jquery.form.js apparently. So all you have to do, is override where ajax.form.ajaxSubmit(ajax.options); is called: Drupal.ajax.prototype.eventResponse.

The result inside my failed-attempt-module.

It's an override of Drupal.ajax.prototype.eventResponse. I've added everything inside if ( 'FormData' in window )

My original plan (as the module name says) was to make all file fields drop containers for HTML5 File drag/drop. My approach was flawed too. I think with this approach, it's not so difficult. Just extend the FormData object at the right time.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.