Tuesday, June 18, 2013

ExtJs Multiple file Upload Control

In this post I'm gonna explain a multiple file upload control developed myself in ExtJs. I had a tough time searching for a multi file uploader in ExtJs. But I couldn't find any such control as per my requirement. Finally I did develop a control, which I wanna share with you guys.

I am using ExtJs normal single file upload control. Upon file selected the file upload control will be pushed down and make it hidden in the below panel. At the same time another panel will be displayed below , which will show the filename, attach icon and a remove button. Another file upload control will be created for the user to select next file . This process will get repeated and the user can put as many files as he can in the form. Finally when the form get submitted you will get these files in the server side.

You can remove added files as well. I have added file validation before adding the file too.

You can add or remove file extensions as you needed in the accept property array defined here

 Here is the javascript code

/* File Created: June 14, 2013 */
/* Author : Sebastian */
Ext.define("YourApp.view.util.Multiupload", {
    extend: 'Ext.form.Panel',
    border: 0,
    alias: 'widget.multiupload',
    margins: '2 2 2 2',
    accept: ['pdf', 'jpg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'bmp', 'tif', 'zip'],
    fileslist: [],
    frame: false,
    items: [
        {
            xtype: 'filefield',
            buttonOnly: true,
            listeners: {
                change: function (view, value, eOpts) {
                    //  alert(value);
                    var parent = this.up('form');
                    parent.onFileChange(view, value, eOpts);
                }
            }

        }

    ],
    onFileChange: function (view, value, eOpts) {
        // debugger;
        var fileNameIndex = value.lastIndexOf("/") + 1;
        if (fileNameIndex == 0) {
            fileNameIndex = value.lastIndexOf("\\") + 1;
        }
        var filename = value.substr(fileNameIndex);

        var IsValid = this.fileValidiation(view, filename);
        if (!IsValid) {
            return;
        }


        this.fileslist.push(filename);
        var addedFilePanel = Ext.create('Ext.form.Panel', {
            frame: false,
            border: 0,
            padding: 2,
            margin: '0 10 0 0',
            layout: {
                type: 'hbox',
                align: 'middle'
            },
            items: [

                {
                    xtype: 'button',
                    text: null,
                    border: 0,
                    frame: false,
                    iconCls: 'button-close',
                    tooltip: 'Remove',
                    listeners: {
                        click: function (me, e, eOpts) {
                            var currentform = me.up('form');
                            var mainform = currentform.up('form');
                            var lbl = currentform.down('label');
                            mainform.fileslist.pop(lbl.text);
                            mainform.remove(currentform);
                            currentform.destroy();
                            mainform.doLayout();
                        }
                    }
                },
                {
                    xtype: 'label',
                    padding: 5,
                    listeners: {
                        render: function (me, eOpts) {
                            me.setText(filename);
                        }
                    }
                },
                {
                    xtype: 'image',
                    src: 'assets/images/attach.png'

                }
            ]
        });

        var newUploadControl = Ext.create('Ext.form.FileUploadField', {
            buttonOnly: true,
            listeners: {
                change: function (view, value, eOpts) {

                    var parent = this.up('form');
                    parent.onFileChange(view, value, eOpts);
                }
            }
        });
        view.hide();
        addedFilePanel.add(view);
        this.insert(0, newUploadControl);
        this.add(addedFilePanel);


        // alert(filename);
    },

    fileValidiation: function (me, filename) {

        var isValid = true;
        var indexofPeriod = me.getValue().lastIndexOf("."),
            uploadedExtension = me.getValue().substr(indexofPeriod + 1, me.getValue().length - indexofPeriod);
        if (!Ext.Array.contains(this.accept, uploadedExtension)) {
            isValid = false;
            // Add the tooltip below to
            // the red exclamation point on the form field
            me.setActiveError('Please upload files with an extension of :  ' + this.accept.join() + ' only!');
            // Let the user know why the field is red and blank!
            Ext.MessageBox.show({
                title: 'File Type Error',
                msg: 'Please upload files with an extension of :  ' + this.accept.join() + ' only!',
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
            // Set the raw value to null so that the extjs form submit
            // isValid() method will stop submission.
            me.setRawValue(null);
            me.reset();
        }

        if (Ext.Array.contains(this.fileslist, filename)) {
            isValid = false;
            me.setActiveError('The file ' + filename + ' already added!');
            Ext.MessageBox.show({
                title: 'Error',
                msg: 'The file ' + filename + ' already added!',
                buttons: Ext.Msg.OK,
                icon: Ext.Msg.ERROR
            });
            // Set the raw value to null so that the extjs form submit
            // isValid() method will stop submission.
            me.setRawValue(null);
            me.reset();
        }


        return isValid;
    },
});

once this javascript file created in your view . you can put it in your form with an xtype 'multiupload'

Here is the screen shot

Cheers ! Happy coding !

16 comments:

  1. Hi Sebastian,

    Can you share the code to this mail dineshharaveer207@gmail.com.

    ReplyDelete
    Replies
    1. Hi Dinesh,
      I remember you asked me about filesize checking before uploading. Please refer my new post
      Thank you

      Delete
  2. Hello Sebastian, congratulations for the post, this will help many colleagues who are looking for this solution.

    Please, I'm trying to deploy your code in ASP.NET MVC and RAZOR 4, you could send a sample of your code in the email javahti@gmail.com ???

    ReplyDelete
  3. Hi, i just implemented and works great but dont have any idea on how to upload those files. I don't even see an "upload" button. Can you share the upload code please? Appreciate it

    ReplyDelete
    Replies
    1. Hi
      Uploading logic you have to implement .
      On clicking the upload button you may have to post the form to server side
      In the server side you will get the form contents including the files you have added

      Delete
  4. Thank you much for the post. It could fix one of the issue that I was facing.

    ReplyDelete
  5. Hi Sebastian Louis,
    I want list out all file names just after the browse button not as below the button how can achieve this

    ReplyDelete
  6. Hi ,
    You can do this by layout changes. In this example I have created a panel containing label for showing file name and a delete button below the browse button the button .
    In my current version I use a grid panel to hold the filenames list.
    You can change the layout to show the file names on the right side of browse button as well. But I'm not clear about your requirement since the files can go many so it is better to keep below so that it can grow downwards rather than sideways !
    Cheers..!!

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Hi Sebastian,
    i am new to extjs , i have extra form filed like textarea , combobox in form.but using ur code i am getting the below err:
    :283 Uncaught TypeError: Cannot read property 'onFileChange' of undefined
    .
    Help me to figure out the issue.

    i am using 4.2 version.

    Thanks.

    ReplyDelete
    Replies
    1. Hi ,
      onFileChange Function is defined in the Multiupload class. It extends a form class. It seems you are doing something wrong. Please try to debug . It seems
      var parent = this.up('form');
      Returns undefined in your case

      Delete
    2. ok thanks.. i found the issue.

      Delete
  9. Hi Sebastian,
    How to remove all the Uploaded Files before Submit .
    I am using 5.1 Version.

    Thanks.

    ReplyDelete
    Replies
    1. Hi ,
      May I know why do you want to remove uploaded files before submit?

      Delete
  10. Please consider this as a request, While writing function pls update it's use and working.. if it's there more easy to identify. And Thank you for your grate effort..

    ReplyDelete