Internet Explorer 10 & 11 do not support HTML5 drag and drop file input form submissions.

by Landon | Jun 21, 2017 | Leave a comment

So, I’m working on a front-end widget in asp.net mvc wherein a user is supposed to be able to upload a spreadsheet to the application I’m working on. The requirements as to the submission method for this particular form were that end users needed to be able to submit it by dragging and dropping, or by clicking a “Browse” link that would open a file upload dialog.

Drag and drop + browse to upload

Those who’ve worked with file uploads before know the HTML for this input is fairly simple: <input type="file" />

However, it’s a bit more complicated than that in this case.

Because I’m working in asp.net MVC, front-end validation is typically done in an unobtrusive fashion. Microsoft designed it so that all a dev needs to do is decorate model members with validation attributes. [Required], and the like. For this particular application, I had to design my own validation attribute to determine whether or not the file type of a submitted file is of the correct extension: [FileTypeValidation(Extensions = ".xlsx", ErrorMessage = "Submitted file must be an .xlsx file.")] (see the end for the code behind this.)

After decorating the view model with this attribute, the front-end validation methods did their job, and it became impossible for someone to submit a non-xlsx file and be able to proceed. Rather than a simple <input type="file" />, my input element became <input accept=".xlsx" aria-label="Choose File" data-val="true" data-val-filetype="Submitted file must be an .xlsx file." data-val-filetype-regex="(\.xlsx)$" data-val-required="The Spreadsheet field is required." id="UploadFile" name="Spreadsheet" tabindex="-1" type="file" value="">, and unobtrusive validation took care of the rest. Pretty standard in asp.net mvc.

However, in IE 11, it also became impossible for someone to submit the file by dragging and dropping.

Starting in IE 10, Microsoft enabled the drag and drop feature of the HTML5 file api for use by developers. This api allows developers to manipulate the DOM through drag and drop. It’s the engine behind the spiffy UI’s where, when a file is uploaded, the user instantly sees details about the file appear on the webpage. It’s incredibly useful.

On the downside, how Microsoft decided to make the default action on drop events an “open/save” action in IE 10/11. That’s all well and good, unless you don’t want that as an action on an <input type="file" /> element.

“No big deal,” you might be thinking. “I’ll just use javascript to place the file upload using that API.”

If that’s what you’re thinking, you thought wrong. The files element belonging to a drop event’s target member (event.target.files) is read-only, meaning one cannot programmatically alter what files will be submitted through the form. Only users can do that by clicking the file input and going through the file upload dialog.

So, let’s sum up: In IE 10/11, you can execute a drag and drop and have access to all of a file’s data through the file api, but you can’t actually upload the file with a drag and drop as you would if you went through the upload file dialog.

Lame sauce. Internet Explorer is total lame sauce.

How to get around this? Use the file api to save dragged and dropped files into a javascript variable. Then, on form submission, ignore the default action and build a new FormData object that can be submitted via ajax. Here’s a great tutorial on how to do this.

The caveat: Do this, and that pretty validation attribute instantly becomes useless. Totally useless.

Ultimately, the best way to get around this problem is to make another input (either text/hidden) and make the value of that only programmatically alterable. When someone submits a file, you store the filename in that input and do validation on the filename. Then, when you submit, call your validation on your inputs. If the validation passes, submit the form via ajax. (Reference that earlier tutorial.)

It was decided that the effort wasn’t worth the energy I would need to invest in order to make that happen, so I don’t have an implementation to share. Instead, I’ll share the validation attribute and the front-end jquery unobtrusive validation adapter I wrote in order to do file type validation on the <input type="file" /> element.

    //file type validation attribute - validates file types of submitted files to ensure the file

    public class FileTypeValidationAttribute : ValidationAttribute, IClientValidatable
    {
        public string Extensions {
            get {
                return string.Join(",", _extensions);
            }

            set {
                _extensions =  value.Split(',');
                //force leading period on entry for each extension
                _extensions.ToList().ForEach(e => e = (e[0] != '.') ? '.' + e : e);
            }
        }

        private string _regexString {
            get { return "(\\" + string.Join("|\\", _extensions) + ")$"; }
        }

        private string[] _regexExtensions {
            get {
                return _extensions.Select(e => "\\" + ((e[0] != '.') ? '.' + e : e) + "$").ToArray();
            }
        }

        private string[] _extensions { get; set; }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var file = (HttpPostedFileWrapper)value;
            if(file != null)
            {
                foreach (var _ext in _regexExtensions)
                {
                    if (Regex.IsMatch(file.FileName, _ext, RegexOptions.IgnoreCase)) return null;
                }
            }

            return new ValidationResult(this.ErrorMessageString);
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var FileTypeRule = new ModelClientValidationRule {
                ErrorMessage = this.ErrorMessageString,
                ValidationType = "filetype",
            };

            FileTypeRule.ValidationParameters.Add("regex", _regexString);

            yield return FileTypeRule;
        }
    }
//the unobtrusive jquery validation adapters that enable front-end validation on the data-val-filetype* attributes of the file input element
$.validator.unobtrusive.adapters.add("filetype", ["regex"], function (options) {
    options.rules["FileTypeValidation"] = options.params.regex;
    options.messages["FileTypeValidation"] = options.message;
});

$.validator.addMethod("FileTypeValidation", function (value, element, param) {
    var patt = new RegExp(param, 'i');
    if (patt.test(value)) return true;
    else return false;
});