Uploading files with Dropzone.js and Express.js

Tweet about this on TwitterShare on LinkedIn0Share on Google+1Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page

Dropzone.js and Express.js File upload

In this post, we will take a look at how to integrate Dropzone.js with Express.js and save files to the server in easy steps. We will configure our app to show a progress bar, load previously saved files and delete files (from the server).

The final product would look like

Screen Shot 2014-09-07 at 3.17.10 pmScreen Shot 2014-09-07 at 3.16.40 pm

You can find a demo here and complete code here.

So, let us get started.

Getting started

There are 2 pieces to the file upload component. One the server side, which will be powered by Express.js. We will be using an existing file upload component which I have written for managing file uploads using blueimp jquery file upload. You can check out the complete post here : Uploading files made fun with Express js and Blueimp file upload.

Two the client side. For this post, we will be using Dropzone.js as the file upload interface.

We will start off by scaffolding a new Express.js project. Generally I use slush-express, a slush generator to scaffold my Express.js apps.

Create a new folder named dropzoneFileupload and open a new terminal/prompt here. First, we will setup slush , gulp  and slush-express globally. Run

Windows Mac/*Nix
npm i -g slush gulp slush-express    sudo npm i -g slush gulp slush-express

Next, we will scaffold a new Express.js app. Run

slush express

You can answer the questions as below

Slush will take a couple of minutes to scaffold the app and download the dependencies. Once that is done, you can run

gulp

to start a new server at port 3000 . And if you navigate to http://localhost:3000 , you will see the sample welcome page.

Setup Server

The first thing we are going to do is setup the server side code. For that, we will be using blueimp-file-upload-expressjs node module. Run

npm i --save blueimp-file-upload-expressjs

This will download blueimp-file-upload-expressjs dependency. Next, we will configure blueimp-file-upload-expressjs. Inside routes folder, create a new file named uploadManager.js. Open it up in your favorite editor and update it as

Things to notice

Line  1 : We set up the minimal options needed to run the file upload server

Line 10 : We require blueimp-file-upload-expressjs module and pass the options as parameter

Line 13 : This is the GET endpoint to fetch the saved files

Line 19 : This is the POST endpoint to save a file

Line 25 : This is the DELETE endpoint to remove a file

Simple right?

PS : You can also upload the files to Amazon S3 with blueimp-file-upload-expressjs module.

PS : You can check out blueimp-file-upload-expressjs module home page to see a few more config options

Next, open routes/index.js and upload it as below

Things to notice

Line 4 : We add a reference to uploadManager and pass the router object.

That is it. Your server is ready!!! To test the server, make sure gulp  is running and navigate to  http://localhost:3000/upload  and you should see an empty files array returned.

Setup client & Integrate with server

Now, we will configure the client. To manage client side dependencies we will use bower. Bower is already baked into the generator, all we need to do is set it up.

Open .bowerrc and update it as

This will dump all the bower dependencies to public/lib folder. Now, run

bower install --save https://github.com/enyo/dropzone.git#~3.10.2

 

This will download dropzone and its required files. Next, we will update views/index.html to include the dependencies. Update views/index.html as below

PS : We will create app.js in a moment

Things to notice

Line 8 :  We include dropzone css, needed for default styling

Line 9 : We include jquery to handle GET/POST/DELETE requests. We are not going to init Dropzone.js using jquery

Line 11 : Include Dropzone.min.js for the functionality. duh!

Line 12 : app.js to configure the plugin

Line 22 : A custom progress bar

Line 26 : Dropzone file upload holder

Next, create a new folder inside the public folder named js and create a new file named app.js inside it. Update it as below

Things to notice

Line 2 : Hook into the init()  to  configure and register Dropzone

Line 5,6 : Enable delete link and set the text

Line 9 : Fire an Ajax call to our GET endpoint to get all previously saved files

Line 13 : We create a mockFile object from the data returned from the GET request.

Line 19,20 : We add the mockFile and set the image as thumbnail. All this data will be dispatched by the blueimp-file-upload-expressjs module.

Line 29 : Hook into addedfile event (if needed you can tap into this event, I have not used here)

Line 34 : Hook into sending event. The callback gets triggered when the upload of the file begins. Here we make the progress bar visible.

Line 40 : Hook into totaluploadprogress event. The callback dispatches progress values. Which we will be using to show the progress in UI.

Line 45 : Hook into queuecomplete event. When this event is triggered, all the uploads are completed and here, we hide the progress bar.

Line 50 : Hook into removedfile event. When the user clicks on delete, we fire an AJAX call to the server with Method type as DELETE. This will remove the file from server. You can tap into the success callback if needed.

That is all the config you need to integrate Dropzone with Express.js. Simple right? And finally, we will add a bit of styles. Open stylesheets/style.css and update as below

Save all the files and refresh  http://localhost:3000  and you should see

Screen Shot 2014-09-07 at 3.17.10 pm Screen Shot 2014-09-07 at 3.16.40 pmSimple and easy right!!

Hope you got a basic understanding on how to integrate Dropzone.js with Express.js.


Thanks for reading! Do comment.
@arvindr21

 

 

Tweet about this on TwitterShare on LinkedIn0Share on Google+1Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page
  • Gustavo Andriuolo

    Hi, u can add: self.files.push( mockFile ); for add the uploaded files to the queue (are not uploaded again)so that previous uploaded files are counted for maxfiles value especified.
    Also you can add self.emit(“success”, mockFile, files[i].id); to add the Green success upload image to the already uploaded files!

  • Pratham

    Can anyone give me the folder already made with the contents shown above?

  • Wilson Novido

    Hi,

    Got this error when I do npm i –save blueimp-file-upload-expressjs
    I’m using Windows 8.
    I’m hoping that you can help me.

    Thanks,
    Wilson

    C:Userswilso_000TutorialsFileUploaddropzoneFileuploadnode_modulesblueimp-file-upload-expressjsnode_moduleslwipbuildlwip_decoder.vcxproj(20,3): error MSB4019: The imported project “C:Microsoft.Cpp.Default.props” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

    C:Userswilso_000TutorialsFileUploaddropzoneFileuploadnode_modulesblueimp-file-upload-expressjsnode_moduleslwipbuildlwip_encoder.vcxproj(20,3): error MSB4019: The imported project “C:Microsoft.Cpp.Default.props” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

    C:Userswilso_000TutorialsFileUploaddropzoneFileuploadnode_modulesblueimp-file-upload-expressjsnode_moduleslwipbuildlwip_image.vcxproj(20,3): error MSB4019: The imported project “C:Microsoft.Cpp.Default.props” was not found. C onfirm that the path in the declaration is correct, and that the file exists on disk.

  • hardik

    I want to upload large files with chunk upload using dropzone.js and express framework. How can I ?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      You can use the above node module to do that.

  • nagarjuna

    i am facing an issue that upload the folders using dropzonejs checking for solution….

    function readDirectory(entries, parentNode) {

    for (i = 0; i < entries.length; i++) {

    if (entries[i].isDirectory) {

    appendItem(entries[i].name, 'folder', parentNode);

    var directoryReader = entries[i].createReader();

    getAllEntries(

    directoryReader,

    readDirectory,

    appendIndentList(parentNode)

    );

    } else {

    appendItem(entries[i].name, 'file', parentNode);

    entries[i].file(appendFile, errorHandler);

    }

    }

    }

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      What is the issue? & which browser?

  • nagarjuna

    Hi can we upload the folder in the filesystem using angularjs (images can be uploaded but folder based images on bulk upload)

  • Andy

    Hey Arvind, Great tutorial. Thanks. I need to dynamically create the upload directory while uploading images like every project should have the specific directory. do you have any suggestion to make it happen. How I can change the uploadDir dynamically in the options

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Andy. As of now, the node module does not support it. You can fork the repo and pass in the folder name of your preference to the post() and then use that in the module while saving the files.

      Do let me know if you need more info. Thanks.

  • bheem

    It is good, how can i add some more form fields to the index.html , so that i can send formdata along with uploaded files.
    Thnks in advance

  • Victor

    Hi, thanks for the tutorial, i’m new in Express. I would like to add your code to my own app, which is an user authenticate app with mogodb, but i don’t know how to create a user specific folder, where they can save their own images, and not in a general folder for everyone, and of course access to that folder.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello Victor. Thanks! The request you have made seems to be a common one. I will write a blog post on this one — How to upload user specific files. — Thanks.

      • Ace Corpuz

        please do! :) thanks in advance

  • Brian from Indiana

    I am a Javascript newbie. I would like to run a shell script to process each file after it is uploaded, and I am having an awful time. I can’t figure out how/where to set up the proper requires to run spawn.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello Brain!

      The straight forward answer to your question is after the upload is completed

      But, What exactly are you trying to do with the shell script?

      Thanks.

      • Brian from Indiana

        I need to pass the uploaded file as an argument to a program, and then return the result (another file) back to the requesting client.

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          If I am not wrong, you are performing a Image processing and returning the updated image. In that case, try this

          and your program should look like

          Does this make sense?

          Thanks!

          • Brian from Indiana

            I am almost getting it figured out. The program I want to invoke to process the file requires a *filename* as its argument, and it produces a file as output. I assume that obj in the context above is the file contents, not the filename?

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            As of now, the obj contains

            if you want the file path on the hard disk, you can construct it on the fly like

            and inside your function, updated the response object with new data.

            Thanks!

          • Brian from Indiana

            Thank you so much!!! I am working on implementing the solution you lay out above.

            Do you take Paypal donations? This has been extremely helpful to me as I am working on my own and had been struggling with this for many hours.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks Brian! I am doing this to help people out! Want to make the web a better place!

            If you want to contribute, I would recommend helping other people in need, may be on stackoverflow or at your workplace. :)

            And do spread my blog around 😀

            Thanks much.

          • Brian from Indiana

            Sorry I must be misunderstanding one other thing from your advice. I am now trying to pass the name of my uploaded file to my program, and I am copying what you wrote above: It failed–even though it worked when I passed in the name explicitly. So I modified the uploadManager.js like this:

            router.post(‘/upload’, function(req, res) {
            uploader.post(req, res, function(obj) {
            var fileName = obj.name
            console.log(‘Got file name of ‘ + fileName);
            res.send(JSON.stringify(obj));
            });
            });

            When I run it, here is what it logs:

            Got file name of undefined
            POST /upload 200 81ms – 225b

            I can see the object, including the name field, in the Developer Console in Chrome.

            Sorry for the bother.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Failed as in?

            You also need to understand the flow of your program. In the above code,

            If you are introducing a new operation like

            You need to tweek the program as shown above to send the response to the client on the callback from urFxn().

          • Brian from Indiana

            I had everything working fine, except that I had hardwired in the name of the uploaded file in my call to my “urProgram” script. But of course that way it would only work for a single file. But when I tried to generalize it (copying the code verbatim from your example above) my script failed, “No such file.”

            So I removed ALL my code except for the snippet I included above, which simply tries (mimicking your code example above) to set a variable fileName based on the obj.name. I put my code right where yours was,

            Your code was: obj.filePath = options.uploadDir + “/” + obj.name

            My code: var fileName = obj.name;

            But it logs as “undefined.”
            I fetched a fresh copy of your code from git, and all I changed in it was adding that single line (plus a console.log line to print the value) but it behaves as above.

            I also tried eliminating the “var filename = obj.name” and just tried to console.log the value of obj.name, but it still comes up undefined.

            Sorry this will be my last bother I will study before I ask any more questions.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Okay, quick pointer, obj.filePath = options.uploadDir + "/" + obj.name supposed to be a psuedo code. This was my bad.

            The actual syntax would be
            obj.filePath = options.uploadDir + "/" + obj.files[0].name

            The actual structure of obj is

            Thanks!

          • Brian from Indiana

            That was all I needed. I’m sorry for the bother, and very appreciative of your help.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Not an issue. Thanks!

          • Brian from Indiana

            I have made a lot of progress. My application is that the uploaded file is an image file; the outboard program runs an OCR application which converts the image to a text file, which I would like to send back to the client.

            The Express documentation mentions that version 4.8.x or above is required for that functionality (an earlier function sendfile() is deprecated), so I modified your package.json file to obtain the newer version of Express.

            The server appears to have successfully sent the file back to the client. Am I correct in assuming I will have to modify the client code to do something with that data, i.e. create a container in which to display it? As things stand, there is no sign in the client that the file has been received.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Yes, this is a custom functionality and you need to implement it by yourself. Check in the network tab if the response has come back. If not, you will either see a error message or the res.sendFile(); is not getting executed properly.

          • Brian from Indiana

            I hope you won’t mind a few more questions, which are definitely going to show how new I am to this: what is the purpose of the “module.exports = urProgram” line at the end of the script up there? Is it that without that line, the “require (‘./urProgram)” would not work? I have read the stackoverflow page on “module.exports” but I am still confused.

            The output of my program is always going to be a text file, and my “program” is just a shell script that invokes an outboard program on the uploaded file and creates the text file as a result. Will it pay me to wrap that in an object, or would it be possible to just send back the output text file?

            The last question is a trivial one: when I spawn the server, the screen only shows the “Drop files” animation for about 500 ms., not long enough to read it. I can’t find where that “banner” is defined, nor whether there is a timeout parameter that would leave it up for a longer period of time.

            I really appreciate the help and hope this is the last I will need to ask.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hello Brian,

            #1 : Module.exports is same as importing another file into the current file. The urProgram is a new file, that consist of your shell script logic. Instead of cluttering the entire code into one file, we split the file into modules. urProgram is one such module. Take a look at https://www.youtube.com/watch?v=DZ_bRk8JWDM for indepth understanding of module exports.

            #2 : If all you are looking for is creating a new text file on every upload, I recommend using fs.writeFile() (http://stackoverflow.com/a/2497040/1015046) instead of a shell script.
            And wrapping this in an object is more of a design pattern. It is called as the module pattern. This way you can expose many properties from a single object. You can read more from here: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript

            #3 Quickly checked a couple of things, but could not find a hook to manage that. What you can do is set line 207 in dropzone.css to

            and then remove the class using jQuery after x seconds.

            Thanks!

  • somenath

    is there any option by which I can let my server accept duplicate file and store it ?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      What do you mean by duplicate file?

      • somenath ghosh

        files with same name. User can upload same file multiple times or different files with same name

        • somenath ghosh

          Uploading the files in a single request. for multiple request, it’s creating different file , but for single request, it’s creating only 1 file even though I have loaded 3 files with same name.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Fyi : the upload path for all the files is same. So you can’t upload multiple files with same name. OS rules.

            As per my understanding, you want the file with the same name to be overwriten?

  • somenath

    Thanks. I will explore this.

  • Nick McMillan

    Great tutorial! One question, I notice that when we visit the uploaded JSON array at ‘/upload’, the items are sorted alphabetically by filename. Is there a simple way to sort these by timestamp instead?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Nick!

      You can perform your sorting on the server side, just before you are sending the data. For example :

      Thanks.

      • Nick McMillan

        That’s helpful Arvind, however I don’t see how this would sort the output by “date uploaded”. For instance, this is what is made available for each file uploaded:

        {
        name: “filename.PNG”,
        size: 38679,
        deleteType: “DELETE”,
        url: “http://url.com/uploaded/files/filename.PNG”,
        deleteUrl: “http://url.com/uploaded/files/filename.PNG”},

        The issue is that this doesn’t include any information about when the file was uploaded (like a timestamp). So my question is regarding whether it’s possible to sort specifically by date uploaded.

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Oh Sorry Nick. I did not *read* the question properly.

          As of now, the object does not have the time stamp. Let me see if I can add that and push a new version.

          Thanks.

          • lawrence0803

            please am try to validate accepting only mp4 and mp3 file not image how do i go about it thanks

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Fixed it. Pls check [email protected]. You will get a response like

          Now you can run a function to sort the files object.

          Thanks.

          • Nick McMillan

            Fantastic! Thanks so much for your help, and for a great tutorial.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks.