jquery fileupload (raw notes)
//The easiest way to submit additional form data is by adding additional input fields to the upload form:
/*
<form id="fileupload" action="server/php/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="example1" value="test">
<div class="row">
<label>Example: <input type="text" name="example2"></label>
</div>
<!-- ... -->
</form>
*/
//By default, the plugin calls jQuery's serializeArray method on the upload form to gather additional form data for all input fields (including hidden fields). The value of these form fields will be sent to the server along with the selected files.
//*Note: If you set the formData option, these fields won't be sent to the server, since the formData object will override them.
//You can however create a formData object of the form fields manually using jQuery's serializeArray method method:
var formData = $('form').serializeArray();
//Adding additional form data programmatically
//The formData option can be used to set additional form data programmatically, e.g.:
$('#fileupload').fileupload({
formData: {example: 'test'}
});
//Setting formData on upload start
//A common use case is to set the formData option on upload start.
//This can be easily achieved by binding a callback to the "submit" event:
$('#fileupload').bind('fileuploadsubmit', function (e, data) {
// The example input, doesn't have to be part of the upload form:
var input = $('#input');
data.formData = {example: input.val()};
if (!data.formData.example) {
data.context.find('button').prop('disabled', false);
input.focus();
return false;
}
});
//*Note: If the submit event callback returns false, the upload request will not start.
//Setting formData on upload start for each individual file upload
//First, we adjust the upload template and add a new cell with an input field for a file title:
/*
<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>
*/
//The title field has "title[]" as name to account for multi-file request uploads. The "required" attribute is used to prevent the file upload if this field is not filled out.
//Next we need to bind a callback to the "submit" event to gather the form data via the upload row context (the context is set by the UI version of the plugin inside of the add callback to the upload row node):
$('#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();
});
//Setting formData on upload start for each individual file upload for AngularJS version
//(...)
/*
Handling additional form data on server-side
The additional form data will be sent to the server as standard POST parameters.
e.g. an additional input field with the name attribute example1 will arrive on server-side as POST parameter example1.
The same goes for a custom formData object, formData: {example2: 'test'} will arrive on server-side as POST parameter example2.
The provided PHP upload handler already provides a method stub to handle additional form data, the function handle_form_data:
<?php
// ...
protected function handle_form_data($file, $index) {
// Handle form data, e.g. $_REQUEST['description'][$index]
}
// ...
e.g. the formData object {example2: 'test'} can be accessed as $_REQUEST['example2'].
*/
// Does the plugin require a form or file input field?
/*
If you define the url (and probably paramName) Options, you can call the plugin on any element - no form or file input field required - and the drag&drop functionality will still work.
To support browsers without XHR file upload capabilities, a file input field has to be part of the widget, or defined using the fileInput option.
*/
// Is it possible to trigger the file selection dialog programmatically?
//However, another file input button can be used to trigger the file selection and passed as parameter to the fileupload add or send API:
$('#some-file-input-field').bind('change', function (e) {
$('#fileupload').fileupload('add', {
files: e.target.files || [{name: this.value}],
fileInput: $(this)
});
});
// How to use the this keyword inside of the plugin initialization options?
//Just make use of jQuery's each method to set the this keyword to the element node:
$('#fileupload').each(function () {
$(this).fileupload({
fileInput: $(this).find('input:file')
});
});
//How to limit the file selection so users can only select one file?
/*
Just remove the multiple attribute from the file input:
<input type="file" name="files[]">
Note that users can still drag&drop multiple files. To enforce a one file upload limit, you can make use of the 'maxNumberOfFiles' option (see Options).
*/
// Why can't I print the files index in the template for loop?
/*
The template will be rendered for each add call.
As long as the option singleFileUploads is set to true (which is the default), multiple selects/drops get split up into single add calls, so the index will always be 0.
*/
// Why doesn't the file input field show the path of a selected file?
/*
The plugin provides CSS classes for a custom file input button, which doesn't display the selected file name. However they can be removed to display the native browser file input button - see Style Guide.
>> By default, the plugin also replaces the file input button after each file(s) selection. This behaviour can be disabled by setting the option replaceFileInput to false.
*/
// Why is the file input field cloned and replaced after each selection?
/*
The cloning is done for two reasons:
First to make sure a change event is fired even if the same file (or filename) is selected subsequently.
Second to allow upload queues for the iframe transport.
If you have one file input and select e.g. the file "example.jpg" and then you abort the upload for some reason, there will be no change event fired if you select the same file to retry the upload. Replacing the original file input with a clone (and resetting the clone's value property) fixes this problem.
Uploads using the iframe transport rely on the file input field, as iframe transport uploads are simple HTML form uploads with an iframe as POST target. If you select a file with a file input field, the file reference is tied to the input field. Modern browsers also allow to access the selected files via the File API, but for the iframe transport, the input field itself is the only usable reference. You can't select another file with this file input field until the associated form has been submitted, else you will loose the original selection. To allow queuing files with the iframe transport, you have to keep the original input field and add a new input field for the next user selection. So, replacing the original file input with a clone (and keeping the original until it has been used for a form submission) also fixes the queuing problem.
The fileInput option is supposed to be a reference to the collection of file input fields the plugin is listening to for change events. So when the original file input fields are replaced with their clones, the clones have to take their place and the fileInput reference needs to be updated.
The only thing the plugin does regarding file names is remove path information from files reported by older browsers (old IE versions) that don't support the File API.
You can easily bind event handlers for any drag event independently of the plugin with jQuery alone, e.g.:
*/
$('#dropzone').bind('dragleave', function (e) {
// dragleave event handler code
});