File Input

1. Custom File Input

  • A simple file input control which styles browsers default input and adds some extra features
  • If you want advanced functionality, you should consider using dropzone.js or other library.
  • Basic usage is:
     
    
     $('#my-file-input').ace_file_input();
    

2. Options

  • You can use one of the following options:
    1. style default=false. If you set it to well, the large style will be displayed
    2. no_file the text to show when no file is selected
    3. no_icon the icon to show when no file is selected
    4. btn_choose button text when no file is selected
    5. btn_change button text when a file is selected
    6. icon_remove icon to use for remove(reset) button
    7. droppable default=false. set true to enable drag & drop
    8. thumbnail small, large or fit. Used when style options is well
    9. allowExt a list of allowed extensions (whitelist)
    10. denyExt a list of denied extensions (blacklist)
    11. allowMime a list of allowed mime types (whitelist)
    12. denyMime a list of denied mime types (blacklist)
    13. maxSize maximum file size allowed in bytes
    The above allow/deny options, trigger file.error.ace event when an invalid file is selected.
    Please refer to "File Filtering" section for more info.
    $('#my-file-input').ace_file_input({
        style: 'well',
        no_file: 'Click to choose or drag & drop',
        droppable: true, //html5 browsers only
        thumbnail: 'small', //html5 browsers only
    
        maxSize: 100000, //~100 KB
        allowExt:  ['jpg', 'jpeg', 'png', 'gif', 'tif', 'tiff', 'bmp'],
        allowMime: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif', 'image/tif', 'image/tiff', 'image/bmp'] //html5 browsers only
    });
    
    $('#my-file-input2').ace_file_input({
        denyExt:  ['exe', 'php']
    });
    

3. Callbacks

  • There are 3 callback option
  • before_change callback is called when user selects/drops files and before files are displayed.
    Inside it you can return:
    1. a modified file list
    2. true and all files will be kept
    3. false and no files will be kept
    4. -1 and no files will be kept and input will be reset

    Also it accepts following arguments:
    1. files a list of selected/dropped files which is a FileList in modern browsers and a string (filename) array for older browsers
    2. dropped whether files have been dropped or selected

    $('#my-file-input').ace_file_input({
      ...
      ,
     before_change: function(files, dropped) {
        //files is a "File" object array in modern browsers
        //files is a "string" (file name) array in older browsers
    
        //dropped=true if files are drag & dropped
    
        var valid_files = []
    
        for(var i = 0; i < files.length; i++) {
          var file = files[i];
    	  
          if( typeof file === 'string') {
              /older browsers that don't support FileReader API, such as IE
              //here, file is just a filename string
              //if (file is valid) valid_files.push(file);
          } else if( 'File' in window && file instanceof window.File ) {
              //file is a "File" object with following properties
              //file.name
              //file.type (mime type)
              //file.size
              //if (file is valid) valid_files.push(file);
          }
        }
    
    
        return valid_files;
    
        //or
        return true;//original input files
    
        //or
        return false;//all are invalid, but don't reset input
    
        //or
        return -1;//all are invalid, reset input
     }
     
  • before_remove can be used to disable resetting file input, for example during a file upload session:
     $('#my-file-input').ace_file_input({
        ...
    	,
        before_remove : function() {
          if( uploadInProgress) return false;//don't allow resetting
          return true;
        }
     });
     
  • If preview_error is defined, it will be called in case there's an error when building preview of image files:
    $('#my-file-input').ace_file_input({
        ...,
        preview_error : function(filename, error_code) {
           //filename = name of the file that had a problem
           switch(error_code) {
              case 1:
              //FILE_LOAD_FAILED
              break;
    
              case 2:
              //IMAGE_LOAD_FAILED
              break;
    
              case 3:
              //THUMBNAIL_FAILED
              break;
           }
       }
    });
     

4. File Filtering

  • As mentioned in previous sections, you can use the following options and callbacks to filter the list of selected files:
    1. allowExt
    2. denyExt
    3. allowMime
    4. denyMime
    5. maxSize
    6. before_change
  • Please note that when you select a file using file dialog, browser's file input element cannot be modified. It can only be reset (emptied).
    For example if you specify allowExt option to select only image files, but user selects none-image files as well, the browser keeps all selected files but Ace file input shows image files only.
  • When user selects an invalid file file.error.ace event is triggered which has some info about the error.
  • If you call preventDefault on event object, the file control will be reset and becomes empty.
    Otherwise, file control won't be reset and browser keeps all selected files.
    However, Ace file input displays valid files and the $('#my-file-input').data('ace_input_files') returns valid files only.
  •  $('#my-file-input').ace_file_input({
        'allowExt': ['jpg', 'jpeg', 'png']
     })
     .on('file.error.ace', function(event, info) {
    	//info.file_count > number of files selected
    	//info.invalid_count > number of invalid files
    	
    	//info.error_count['ext'] > number of files with invalid extension (only if allowExt or denyExt is set)
    	//info.error_count['mime'] > number of files with invalid mime type (only if allowMime or denyMime is set)
    	//info.error_count['size'] > number of files with invalid size (only if maxSize option is set)
    
    	//info.error_list['ext'] > list of file names with invalid extension
    	//info.error_list['mime'] > ...
    	//info.error_list['size'] > ...
    	
    	//info.dropped > true if files have been selected by drag & drop
    	
    	
    	//if you do this
    	event.preventDefault();
    	//it will reset (empty) file input, i.e. no files selected
     }); 
    
  • There is also before_change callback. Please see previous section for more info.

5. Functions

  • The following functions are available for file input control.
  • show_file_list takes a list of file names and shows them inside the control:
    $('#my-input').ace_file_input('show_file_list', ['file1.txt']);
    
    For example, you may want to edit a file input which has user's previous selection.
    From version 1.3.2 you can also preview images inside file input control.
    $('#my-input')
    .ace_file_input('show_file_list', [
        {type: 'image', name: 'name of image', path: 'http://path/to/image/for/preview'},
        {type: 'file', name: 'hello.txt'}
    ]);
    //type can be 'image', 'video', 'audio', 'file'
    
  • update_settings to update options:
    $('#my-input').ace_file_input('update_settings', {
       allowExt: ['pdf', 'doc', 'docx']
    });
    
  • files returns list of selected files:
    var files = $('#my-input').ace_file_input('files');
    //is similar to:
    var files = $('#my-input').data('ace_input_files');
    
  • method returns method used by user which is 'select' or 'drop':
    var method = $('#my-input').ace_file_input('method');
    //is similar to:
    var method = $('#my-input').data('ace_input_method');
    
  • disable disables file input:
    $('#my-input').ace_file_input('disable');
    
  • enable enables file input:
    $('#my-input').ace_file_input('enable');
    
  • enable_reset takes an argument and enables/disables reset button:
    $('#my-input').ace_file_input('enable_reset', false);
    $('#my-input').ace_file_input('enable_reset', true);
    
  • reset_input resets file input:
    $('#my-input').ace_file_input('reset_input');
    
  • reset_input_ui resets file input's UI only:
    $('#my-input').ace_file_input('reset_input_ui');
    
    Suppose you have a form with a reset button.
    When you hit "reset", file input field will be reset, but Ace file input's UI won't be reset.
    You should do this on your own:
    $('#my-form').on('reset', function(e) {
        $('#my-input').ace_file_input('reset_input_ui');
    });
    
  • reset_input_field resets file input field
  • loading adds/updates/removes a loading/waiting overlay for example during a file upload:
     $('#my-input').ace_file_input('loading' , true);//adds overlay
     $('#my-input').ace_file_input('loading' , false);//removes overlay
     $('#my-input').ace_file_input('loading' , ' custom content inside overlay such as a progressbar ');
    

6. Events

  • If you use file filter options and user selects or drops an invalid file, a file.error.ace event is triggered with some info about invalid files.
    You can find more info about it in the File Filtering section.
  • You can also add a change event listener to the file input and it will be triggered when files are selected or dropped:
     $('#my-file-input').ace_file_input({
       droppable: true
     })
     .on('change', function() {
        var files = $(this).data('ace_input_files');
        var method = $(this).data('ace_input_method');
     });
    

7. Uploading

  • If you don't use drag & drop functionality, file upload is done as normal, by submitting the form and browser takes care of it.
  • However when you enable drag & drop feature and user drops some files onto the control, file field is not modified and by submitting form, no files are uploaded.
  • In this case, you should use modern HTML5 features and upload your files using Ajax and FormData object.
    FormData
  • The list of files which should be uploaded is retrieved like this:
    var files = $('#my-file-input').data('ace_input_files');
    
  • For a working example and more info please see examples/file-upload.html.
  • When using FormData object if you use the following to create your FormData object, browser will include all the files that are selected by user:
    var myform = $('#myform');
    var fd = new FormData(myform.get(0));//populate FormData with myform data
    
    This way our filtered files are not taken into account.
    So you can do the following instead:
    var myform = $('#myform');
    var fd = new FormData();//empty FormData object
    $.each(myform.serializeArray(), function(i, item) {
      //add form fields one by one to our FormData 
      fd.append(item.name, item.value);
    });
    
    The above does not add file fields to FormData and we should append our files like this:
    myform.find('input[type=file]').each(function(){
      var field_name = $(this).attr('name');
      //for fields with "multiple" file support
      //field name should be something like `myfile[]`
    
      var files = $(this).data('ace_input_files');
      if(files && files.length > 0) {
         for(var f = 0; f < files.length; f++) {
           fd.append(field_name, files[f]);
        }
      }
    });
    
    Now our FormData object can be submitted using Ajax:
    var deferred = $.ajax({
              url: myform.attr('action'),
             type: myform.attr('method'),
      processData: false,//important
      contentType: false,//important
         dataType: 'json',//depending on your server side response
             data: fd//our FormData object
    })
    
    deferred.done(function(result) {
      //on success (successful response from server)
    }).fail(function(result) {
      //unable to receive a valid response from server
    });
    
  • For older browsers that don't support FormData object, we can use an invisible frame to upload our form without leaving or refreshing the page:
    var deferred = new $.Deferred //create a custom deferred object, because there's no ajax here to create it for us
    var temporary_iframe_id = 'temporary-iframe-'+(new Date()).getTime()+'-'+(parseInt(Math.random()*1000));
    var temp_iframe = 
         $('<iframe id="'+temporary_iframe_id+'" name="'+temporary_iframe_id+'" \
           frameborder="0" width="0" height="0" src="about:blank"\
           style="position:absolute; z-index:-1; visibility: hidden;" />')
          .insertAfter(myform)
    
    myform.append('<input type="hidden" name="temporary-iframe-id" value="'+temporary_iframe_id+'" />');
    
    temp_iframe.data('deferrer' , deferred);
    //we save the deferred object to the iframe and in our server side response
    //we use "temporary-iframe-id" to access iframe and its deferred object
    
    myform.attr({
           'method': 'POST',
          'enctype': 'multipart/form-data',
           'target': temporary_iframe_id //important
    });
    
    myform.get(0).submit();
    
    //if we don't receive a response after 30 seconds, let's declare it as failed!
    ie_timeout = setTimeout(function(){
        ie_timeout = null;
        temp_iframe.attr('src', 'about:blank').remove();
        deferred.reject({'status':'fail', 'message':'Timeout!'});
    } , 30000);
    }
    
    And deferred callbacks are similar to ajax example.

8. Notes

  • Please note that validating files inside browser is not secure.
    You should always check uploaded files in your server side script.
    A php example inside examples/file-upload.php validates files and only allows image files.
  • Most modern browsers allow multiple file selection.
    If you want that, make sure your file input control has multiple attribute and input name has brackets like myfiles[]:
     <input multiple type="file" name="myfiles[]" id="myfiles" />