ExtJS: an easy way to multi-load and validate files (use the HTML5 File API)
- Tutorial
If you need to validate user-downloaded files not only on the server, but also on the client, or if you want to allow the user to select several files to upload at once (multiple = "multiple"), then most likely you will encounter some difficulties when using Ext.form .field.File.
Checking the extension of the downloaded file, if the user has selected only one file, is not difficult - just declare vtype and look at the value input:
Problems begin when there are several files, and / or you need to check the "weight" of the file. The thing is that in the code above, the field does not refer to input, in which the selected files "lie", but to the table in which input lies.
It’s easy enough to get to the input itself:
If someone does not understand, then the line above on vanilla.js will sound like this:
Vanilla probably would have saved some matches, but I don’t really like when porridge starts, and my body does not feel the difference in work.
If there is only one file, and you do not mind using a non-native input to download files, then the problem is solved (you could say it wasn’t) - we get the file download field and use the File API to validate the weight of the file. Otherwise, some problems remain:
1. If you select several files (after some manipulations), the field on the form will show you only the first selected file.
2. If you want a native input - its size attribute will be 1, after setting inputType: 'file' in the field configuration, and setting the size: 50 property will not help you.
On the question of using native browser elements - there is no desire to hang around on this topic - I just prefer to use them if the element has any kind of behavior, and if there is such an opportunity. It's just more familiar for the user - he knows what to expect from this thing.
Although, if a little distracted from the topic, when FF in one of the recent updates adopted the Chrome-style behavior of the placeholder attribute (the text stopped disappearing when focusing on the field) - it slightly bothered me. I don’t understand what are the advantages of this behavior - I always want to erase this text before entering it.
If you google, the Internet, in most cases, will advise you to validate files only on the server, or use flash. If you want and can - you can do so. I also saw ux , which can load a lot of files and validate them - it can also be an option.
And you can do just a few lines, and use the File API. At the same time, all sorts of IEs have fallen off, but personally I don’t have much worries about this - the download option still remains, and the server still validates. In addition, if you use ext and write a more or less complicated application, then most likely you can dictate browsers to the end user.
We proceed as follows - we will inherit from textfield, set inputType: 'file' to it, let us set the size of the input and the multiple attribute in the configuration. Assign alias to all this business for short access (xtype). We will describe validation rules by vtype. All this will allow you to use the field with the desired behavior many times in any view of the application, and configure it flexibly (for example, set the allowed file types and their maximum size).
I don’t even know if something needs explanation. If in a nutshell - after the "drawing" of the native input, the size attribute is set for it (set during configuration or by default - 1) and the multiple attribute if it is set in the configuration. So now we have a native configurable input.
Here, I think, everything is also quite clear. Just set the default file types / sizes, get input and go over its files - check their type / size. Everything is very simple.
Now we can load and validate the files, describing the form field as follows:
In action, all this economy can be seen here - everything is assembled into one file for clarity, although in general I love MVTS 4th ext.
The essence of the problem
Checking the extension of the downloaded file, if the user has selected only one file, is not difficult - just declare vtype and look at the value input:
Ext.apply(Ext.form.field.VTypes, {
file: function(val, field) {
var types = ['rtf', 'pdf', 'doc'],
ext = val.substring(val.lastIndexOf('.') + 1);
if(Ext.Array.indexOf(types, ext) === -1) {
return false;
}
return true;
}
,fileText: 'Invalid file'
});
Problems begin when there are several files, and / or you need to check the "weight" of the file. The thing is that in the code above, the field does not refer to input, in which the selected files "lie", but to the table in which input lies.
It’s easy enough to get to the input itself:
var input = Ext.get(field.id+'-fileInputEl'); - и мы можем работать с input.files.
If someone does not understand, then the line above on vanilla.js will sound like this:
var input = document.getElementById(field.id+'-fileInputEl');
Vanilla probably would have saved some matches, but I don’t really like when porridge starts, and my body does not feel the difference in work.
If there is only one file, and you do not mind using a non-native input to download files, then the problem is solved (you could say it wasn’t) - we get the file download field and use the File API to validate the weight of the file. Otherwise, some problems remain:
1. If you select several files (after some manipulations), the field on the form will show you only the first selected file.
2. If you want a native input - its size attribute will be 1, after setting inputType: 'file' in the field configuration, and setting the size: 50 property will not help you.
On the question of using native browser elements - there is no desire to hang around on this topic - I just prefer to use them if the element has any kind of behavior, and if there is such an opportunity. It's just more familiar for the user - he knows what to expect from this thing.
Although, if a little distracted from the topic, when FF in one of the recent updates adopted the Chrome-style behavior of the placeholder attribute (the text stopped disappearing when focusing on the field) - it slightly bothered me. I don’t understand what are the advantages of this behavior - I always want to erase this text before entering it.
Decision
If you google, the Internet, in most cases, will advise you to validate files only on the server, or use flash. If you want and can - you can do so. I also saw ux , which can load a lot of files and validate them - it can also be an option.
And you can do just a few lines, and use the File API. At the same time, all sorts of IEs have fallen off, but personally I don’t have much worries about this - the download option still remains, and the server still validates. In addition, if you use ext and write a more or less complicated application, then most likely you can dictate browsers to the end user.
We proceed as follows - we will inherit from textfield, set inputType: 'file' to it, let us set the size of the input and the multiple attribute in the configuration. Assign alias to all this business for short access (xtype). We will describe validation rules by vtype. All this will allow you to use the field with the desired behavior many times in any view of the application, and configure it flexibly (for example, set the allowed file types and their maximum size).
We describe the field:
Ext.define('fileupload',{
extend: 'Ext.form.field.Text'
,alias: 'widget.fileupload' // теперь мы можем написать xtype: 'fileupload'
,inputType: 'file'
,listeners: {
render: function (me, eOpts) {
var el = Ext.get(me.id+'-inputEl');
el.set({
size: me.inputSize || 1
});
if(me.multiple) {
el.set({
multiple: 'multiple'
});
}
}
}
});
I don’t even know if something needs explanation. If in a nutshell - after the "drawing" of the native input, the size attribute is set for it (set during configuration or by default - 1) and the multiple attribute if it is set in the configuration. So now we have a native configurable input.
We describe the validator:
Ext.apply(Ext.form.field.VTypes, {
file: function(val, field) {
var input, files, file
,acceptSize = field.acceptSize || 4096 // Максимальный вес файлов
,acceptMimes = field.acceptMimes || ['rtf', 'pdf', 'doc', 'xls', 'xlsx', 'zip', 'rar']; // Разрешенные типы
input = Ext.get(field.id+'-inputEl');
files = input.getAttribute('files');
if ( ! files || ! window.FileReader) {
return true; // Мы имеем дело с неправильным браузером. Из вредности можно вернуть и false
}
for(var i = 0, l = files.length; i < l; i++) { // смотрим размеры файлов
file = files[i];
if(file.size > acceptSize * 1024) {
this.fileText = (file.size / 1048576).toFixed(1) + ' MB: invalid file size ('+(acceptSize / 1024).toFixed(1)+' MB max)';
return false;
}
var ext = file.name.substring(file.name.lastIndexOf('.') + 1);
if(Ext.Array.indexOf(acceptMimes, ext) === -1) { // смотрим расширения файлов
this.fileText = 'Invalid file type ('+ext+')';
return false;
}
}
return true;
}
});
Here, I think, everything is also quite clear. Just set the default file types / sizes, get input and go over its files - check their type / size. Everything is very simple.
Now we can load and validate the files, describing the form field as follows:
{
xtype: 'fileupload'
,vtype: 'file'
,multiple: true // разрешаем выбрать несколько файлов
,acceptMimes: ['doc', 'xls', 'xlsx', 'pdf', 'zip', 'rar'] // Устанавливаем разрешенные типы
,acceptSize: 2048 // Максимальный размер
,inputSize: 76 // Атрибут size
,fieldLabel: 'File (doc, xls, xlsx, pdf, zip, rar; 2 MB max)'
,msgTarget: 'under'
,name: 'filesToUpload[]'
}
In action, all this economy can be seen here - everything is assembled into one file for clarity, although in general I love MVTS 4th ext.