Tigzy
Tigzy

Reputation: 181

Jquery File Upload add extra upload fields

I'm using Jquery-File-Upload for my upload page, and I'm having a problem to add extra upload fields.

I'm following that page: https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-form-data

It works well for 1 file submission. However, with multiple files submission we are starting to see issues, because files are uploaded 1 file / POST (singleFileUploads: true).

The code I'm using as reference is the following:

<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <!-- ... -->
        <td class="title"><label>Title: <input name="title[]" required></label></td>
        <!-- ... -->
    </tr>
{% } %}
</script>

If you submit that with 2 files, then you get 2 POSTS:

1/

$_REQUEST: 
(
  title:
  (
    [0] -> Title1
    [1] -> Title2
  )
)

$_FILES:
(
  [0] -> ( 'name' => 'file name 1', ... )
)

2/

$_REQUEST: 
(
  title:
  (
    [0] -> Title1
    [1] -> Title2
  )
)

$_FILES:
(
  [0] -> ( 'name' => 'file name 2', ... )
)

Then, on php side, the function handle_form_data relies on file index

<?php
// ...
    protected function handle_form_data($file, $index) {
        // Handle form data, e.g. $_REQUEST['description'][$index]
    }
// ...

The problem is that index is always 0, because we're uploading 1 file / post. Now you see that since the $_REQUEST uploads all extra fields from all files (no matter what is it the current file), the index from $_FILES gets de-synchronized from the extra fields array.

Do you know any workaround, except turning singleFileUploads to OFF?

Upvotes: 3

Views: 3159

Answers (3)

Mark Reid
Mark Reid

Reputation: 1

Late to answer as well, but I just got done working through the same issue.

There is a key part of the documentation linked above that the OP didn't implement:

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
    var inputs = data.context.find(':input');
    if (inputs.filter(function () {
            return !this.value && $(this).prop('required');
        }).first().focus().length) {
        data.context.find('button').prop('disabled', false);
        return false;
    }
    data.formData = inputs.serializeArray();
});

With this added, the "closest" value for the input field is added to the formData array that is submitted with the form.

More details at: https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-form-data#setting-formdata-on-upload-start-for-each-individual-file-upload

Upvotes: 0

poletaew
poletaew

Reputation: 196

I know, it's too late, but i use easiest way:

<input type="text" name="{%=file.name%}[title]">
<input type="text" name="{%=file.name%}[description]">

Then you get convenient data array for each file by filename, like this:

print_r($_POST);

/* will be:
 * Array
 * (
 *     [file1_jpg] => Array
 *         (
 *             [title] => title 1
 *             [description] => description 1
 *         )
 * 
 *     [file2_jpg] => Array
 *         (
 *             [title] => title 2
 *             [description] => description 2
 *         )
 * 
 *     [file3_png] => Array
 *         (
 *             [title] => title 3
 *             [description] => description 3
 *         )
 * 
 * )
 */

But remember: all dots in $_POST keys will be replaced to underscores! This is normal. Just remember it.

Upvotes: 0

Tigzy
Tigzy

Reputation: 181

Ok, I will answer myself.

First, we will attribute an id to the files as soon as they are added to the UI. We maintain an incremental index for that:

//global
var current_file_index = 0;

Next, we need to play with fileuploadadd callback to add that index to the files:

$('#fileupload').bind('fileuploadadd', function (e, data) {
  for (var i = 0; i < data.files.length; i++) {
    data.files[i].index = current_file_index++;
  }
});

That index is now accessible when adding the files on UI side. We don't want the custom input to be added to the form, so change the name by an id (so that it will not be submitted). And add the brand new index as part of that ID:

<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <!-- ... -->
        <td class="title"><label>Title: <input id="title_{%=file.index%}" required></label></td>
        <!-- ... -->
    </tr>
{% } %}
</script>

Then, when we submit the file(s), we want to add the result of that input to the formData. We don't care about sending to much data, so we basically send the whole files array as JSON string:

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
  for (var i = 0; i < data.files.length; i++) {
    var title = $("title_ + data.files[i].index.toString()").val();
    data.files[i].title = title;
  }

  data.formData = {
    files_data: JSON.stringify(data.files)
  }
});

Don't forget the get the data back on server side in $_REQUEST["files_data"], and explode the json that now contains only 1 file's data).

Upvotes: 2

Related Questions