I am running a Symfony 2.8 based web app which sends some form data back to a controller using Ajax.
So far everything worked fine, but since the latest macOS update
Meanwhile I found this quick and dirty solution. But actually I am looking for a real workaround. Any ideas?
// Filter out empty file just before the Ajax request
// Use try/catch since Safari < 10.13.4 does not support FormData.entries()
try {
for (var pair of data.entries()) {
if (pair[1] instanceof File && pair[1].name == '' && pair[1].size == 0)
data.delete(pair[0]);
}
} catch(e) {}
I used this solution and works for me.
var $form = $('#website_settings_form');
var $inputs = $('input[type="file"]:not([disabled])', $form); //select input files
$inputs.each(function(_, input) {
if (input.files.length > 0) return
$(input).prop('disabled', true) //if the input doesn't have uploaded files will be disable
})
var formData = new FormData($form[0]);// create the form data
$inputs.prop('disabled', false);//enable fields again.
I use FormData throughout my site and can verify that this is a problem with the latest version of Safari. Removing the empty file fixes the problem. Here's the code that worked for me:
var form = $('#formID');
var data = new FormData(form[0])
//hack to fix safari bug where upload fails if file input is empty
if (document.getElementById("fileID").files.length == 0 ) { //if the file is empty
data.delete('fileID'); //remove it from the upload data
}
Andrei Herford's solution will crash other browsers that do not support the entries() method of FormData - using try/catch will only find execution errors, not syntax errors.
Our solution was to use plain JavaScript to remove the empty file input element before creating the FormData object, thus:
for (i = 0; i < form.elements.length; i++) {
if (form.elements[i].type == 'file') {
if (form.elements[i].value == '') {
form.elements[i].parentNode.removeChild(form.elements[i]);
}
}
}
I used Andrei's suggestion, which worked for safari, but broke IE.
The only solution I could find that would work in both browsers was to use eval().
Since this appears to be a bug only affecting safari 11 I also added a check on browser version.
if(dataObj instanceof FormData && navigator.userAgent.match(/version\/11((\.[0-9]*)*)? .*safari/i)) {
try {
eval('for (var pair of dataObj.entries()) {\
if (pair[1] instanceof File && pair[1].name === \'\' && pair[1].size === 0) {\
dataObj.delete(pair[0]);\
}\
}');
} catch(e) {}
}