Javascript required
Skip to content Skip to sidebar Skip to footer

Dropzone Override Init and Upload Server Image

Introduction

In this article, we volition talk nearly how to handle file uploads with VueJs. We will create an images uploader that allow user to upload single or multiple images file past drag and driblet or select file dialog.

We will so upload the selected images and display them accordingly. We will too learn to filter the upload file type, for example, we just allow images, do not allow file type similar PDF.

Image uploader

  • Sourcecode: https://github.com/chybie/file-upload-vue
  • Demo: https://vue-file-upload-1126b.firebaseapp.com/

File Upload UI & API

File upload consists of 2 parts: the UI (front-end) and the API (dorsum-terminate). We will be using VueJs to handle the UI part. We need a backend application to accept the uploaded files. You may follow the backend tutorials or download and run either one of these server side application to handle file upload for your backend:-

  • File upload with Hapi.js: https://scotch.io/bar-talk/handling-file-uploads-with-hapi-js, or
  • File upload with Express + Multer: https://scotch.io/tutorials/express-file-uploads-with-multer, or
  • Switch to any deject solution of your choice (Amazon S3, Google Drive, etc).

We will be using File upload with Hapi.js equally our backend throughout this articles. We will also learn the tricks to enable fake upload on the front-end.

Setup Project with Vue-Cli

We volition exist using vue-cli to scaffold Vue.js projects. We will be using the webpack-simple project template.

                      # install cli            npm            install            vue-cli -g            # then create project, with sass            # follow the instructions to install all necessary dependencies            vue init webpack-simple file-upload-vue                  

Alright, all set. Let's proceed to create our component.

File Upload Component

We will write our code in App.vue. Remove all the machine-generated code in the file.

                      <!-- App.vue -->            <!-- HTML Template -->                                          <template              >                                                      <div              id                              =                "app"                            >                                                      <div              grade                              =                "container"                            >                        <!--UPLOAD-->                                          <course              enctype                              =                "multipart/form-data"                            novalidate              five-if                              =                "isInitial || isSaving"                            >                                                      <h1              >            Upload images                              </h1              >                                                      <div              class                              =                "dropbox"                            >                                                      <input              type                              =                "file"                            multiple              :name                              =                "uploadFieldName"                            :disabled                              =                "isSaving"                            @change                              =                "filesChange($event.target.name, $upshot.target.files); fileCount = $issue.target.files.length"                            accept                              =                "image/*"                            form                              =                "input-file"                            >                                                      <p              v-if                              =                "isInitial"                            >                        Elevate your file(s) here to begin                              <br              >                        or click to browse                                          </p              >                                                      <p              v-if                              =                "isSaving"                            >                        Uploading {{ fileCount }} files...                                          </p              >                                                      </div              >                                                      </form              >                                                      </div              >                                                      </template              >                        <!-- Javascript -->                                          <script              >                                                                                                          </script              >                        <!-- SASS styling -->                                          <style              lang                              =                "scss"                            >                                                                                                          </style              >                              

Notes:-

  1. Our App.vue component consists of 3 part: template (HTML), script (Javascript) and styles (SASS).
  2. Our template has an upload form.
  3. The class attribute enctype="multipart/form-data" is of import. To enable file upload, this attribute must be set. Learn more about enctype hither.
  4. We have a file input <input type="file" /> to take file upload. The property multiple indicate it's allow multiple file upload. Remove it for unmarried file upload.
  5. We will handle the file input modify issue. Whenever the file input modify (someone drop or select files), we will trigger the filesChange role and pass in the control proper noun and selected files $issue.target.files, and and then upload to server.
  6. We limit the file input to have images only with the aspect have="image/*".
  7. The file input will be disabled during upload, and then user tin only driblet / select files once again subsequently upload complete.
  8. We capture the fileCount of the when file changes. We use the fileCount variable in displaying number of files uploading Uploading {{ fileCount }} files....

Manner our File Upload Component

Now, that's the interesting role. Currently, our component look like this:

File upload component without styling

Nosotros demand to transform information technology to look like this:

File upload component with styling

Allow's style it!

                      <!-- App.vue -->            ...            <!-- SASS styling -->            <style lang="scss">            .dropbox {                          outline              :              2px dashed greyness;              /              *              the nuance box              *              /                                      outline-offset              :              -10px;                          background              :              lightcyan;                          color              :              dimgray;                          padding              :              10px 10px;                          min-height              :              200px;              /              *              minimum meridian              *              /                                      position              :              relative;                          cursor              :              pointer;            }            .input-file {                          opacity              :              0;              /              *              invisible simply it's there!              *              /                                      width              :              100%;                          height              :              200px;                          position              :              absolute;                          cursor              :              pointer;            }                          .dropbox              :              hover              {                          background              :              lightblue;              /              *              when mouse over to the drib zone, change colour              *              /                        }            .dropbox p {                          font-size              :              1.2em;                          text-align              :              center;                          padding              :              50px 0;            }            </manner>                  

With only few lines of scss, our component looks prettier now.

Notes:-

  1. Nosotros make the file input invisible by applying opacity: 0 style. This doesn't hibernate the file input, it just brand it invisible.
  2. Then, we mode the file input parent element, the dropbox css class. Nosotros arrive wait like a driblet file zone surround with dash.
  3. And so, nosotros marshal the text inside dropbox to center.

File Upload Component Code

Let'south proceed to code our component.

                      <            !            --            App.vue            --            >            ...            <            !            --            Javascript            --            >            <script>            import            {            upload            }            from            './file-upload.service'            ;            const            STATUS_INITIAL            =            0            ,            STATUS_SAVING            =            1            ,            STATUS_SUCCESS            =            two            ,            STATUS_FAILED            =            3            ;            export            default            {            name            :            'app'            ,            information            (            )            {            return            {            uploadedFiles            :            [            ]            ,            uploadError            :            nothing            ,            currentStatus            :            aught            ,            uploadFieldName            :            'photos'            }            }            ,            computed            :            {            isInitial            (            )            {            render            this            .currentStatus            ===            STATUS_INITIAL            ;            }            ,            isSaving            (            )            {            return            this            .currentStatus            ===            STATUS_SAVING            ;            }            ,            isSuccess            (            )            {            render            this            .currentStatus            ===            STATUS_SUCCESS            ;            }            ,            isFailed            (            )            {            return            this            .currentStatus            ===            STATUS_FAILED            ;            }            }            ,            methods            :            {            reset            (            )            {            // reset form to initial country            this            .currentStatus            =            STATUS_INITIAL            ;            this            .uploadedFiles            =            [            ]            ;            this            .uploadError            =            null            ;            }            ,            save            (            formData            )            {            // upload data to the server            this            .currentStatus            =            STATUS_SAVING            ;            upload            (formData)            .            then            (            x            =>            {            this            .uploadedFiles            =            [            ]            .            concat            (x)            ;            this            .currentStatus            =            STATUS_SUCCESS            ;            }            )            .            catch            (            err            =>            {            this            .uploadError            =            err.response;            this            .currentStatus            =            STATUS_FAILED            ;            }            )            ;            }            ,            filesChange            (            fieldName,              fileList            )            {            // handle file changes            const            formData            =            new            FormData            (            )            ;            if            (            !fileList.length)            render            ;            // append the files to FormData            Array            .            from            (            Assortment            (fileList.length)            .            keys            (            )            )            .            map            (            x            =>            {            formData.            append            (fieldName,            fileList[x]            ,            fileList[x]            .proper noun)            ;            }            )            ;            // relieve it            this            .            save            (formData)            ;            }            }            ,            mounted            (            )            {            this            .            reset            (            )            ;            }            ,            }            <            /script>                  

Notes:-

  1. Our component will take a few statuses: STATUS_INITIAL, STATUS_SAVING, STATUS_SUCCESS, STATUS_FAILED, the variable name is pretty expressive themselves.
  2. Later on, we volition phone call the Hapi.js file upload API to upload images, the API accept a field call photos. That's our file input field name.
  3. We handle the file changes with the filesChange function. FileList is an object returned past the files property of the HTML <input> element. Information technology allow us to admission the listing of files selected with the <input type="file"> element. Acquire more [here]((https://developer.mozilla.org/en/docs/Web/API/FileList).
  4. We then create a new FormData, and suspend all our photos files to it. FormData interface provides a manner to easily construct a set of central/value pairs representing grade fields and their values. Learn more here.
  5. The save function volition phone call our file upload service (hang on, we will create the service next!). Nosotros also set the status according to the result.
  6. mount() is the vue component life cycle claw. During that indicate, we will gear up our component status to initial country.

File Upload Service

Allow's keep to create our service. We volition be using axios to make HTTP calls.

Install axios

                      # install axios            npm            install            axios --save                  

Service

                      // file-upload.service.js            import            *            every bit            axios            from            'axios'            ;            const            BASE_URL            =            'http://localhost:3001'            ;            function            upload            (            formData            )            {            const            url            =                          `                              ${                BASE_URL                }                            /photos/upload              `                        ;            return            axios.            post            (url,            formData)            // get data            .            then            (            x            =>            ten.data)            // add together url field            .            then            (            x            =>            x.            map            (            img            =>            Object.            assign            (            {            }            ,            img,            {            url            :                          `                              ${                BASE_URL                }                            /images/                              ${img.id}                            `                        }            )            )            )            ;            }            export            {            upload            }                  

Zippo much, the code is pretty expressive itself. We upload the files, wait for the result, map it accordingly.

You may run the application now with npm run dev command. Effort uploading a couple of images, and it'south working! (Remember to start your backend server)

Display Success and Failed Result

We can upload the files successfully now. However, in that location's no indication in UI. Allow'south update our HTML template.

                      <!-- App.vue -->            <!-- HTML Template -->                                          <template              >                                                      <div              id                              =                "app"                            >                                                      <div              form                              =                "container"                            >                        ...form...            <!--SUCCESS-->                                          <div              v-if                              =                "isSuccess"                            >                                                      <h2              >            Uploaded {{ uploadedFiles.length }} file(s) successfully.                              </h2              >                                                      <p              >                                                      <a              href                              =                "javascript:void(0)"                            @click                              =                "reset()"                            >            Upload once again                              </a              >                                                      </p              >                                                      <ul              course                              =                "list-unstyled"                            >                                                      <li              v-for                              =                "item in uploadedFiles"                            >                                                      <img              :src                              =                "item.url"                            course                              =                "img-responsive img-thumbnail"                            :alt                              =                "item.originalName"                            >                                                      </li              >                                                      </ul              >                                                      </div              >                        <!--FAILED-->                                          <div              v-if                              =                "isFailed"                            >                                                      <h2              >            Uploaded failed.                              </h2              >                                                      <p              >                                                      <a              href                              =                "javascript:void(0)"                            @click                              =                "reset()"                            >            Try once again                              </a              >                                                      </p              >                                                      <pre              >            {{ uploadError }}                              </pre              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                              

Notes:-

  1. Brandish the uploaded image when upload successfully.
  2. Display the error message when upload failed.

False the Upload in Front-end

If you are lazy to start the back-stop application (Hapi, Express, etc) to handle file upload. Here is a faux service to supplant the file upload service.

                      // file-upload.fake.service.js            function            upload            (            formData            )            {            const            photos            =            formData.            getAll            (            'photos'            )            ;            const            promises            =            photos.            map            (            (            ten            )            =>            getImage            (x)            .            then            (            img            =>            (            {            id            :            img,            originalName            :            10.name,            fileName            :            10.name,            url            :            img            }            )            )            )            ;            render            Promise.            all            (promises)            ;            }            function            getImage            (            file            )            {            render            new            Hope            (            (            resolve,              decline            )            =>            {            const            fReader            =            new            FileReader            (            )            ;            const            img            =            certificate.            createElement            (            'img'            )            ;            fReader.            onload            =            (            )            =>            {            img.src            =            fReader.event;            resolve            (            getBase64Image            (img)            )            ;            }            fReader.            readAsDataURL            (file)            ;            }            )            }            function            getBase64Image            (            img            )            {            const            sheet            =            document.            createElement            (            'canvas'            )            ;            sheet.width            =            img.width;            canvas.height            =            img.top;            const            ctx            =            canvas.            getContext            (            '2d'            )            ;            ctx.            drawImage            (img,            0            ,            0            )            ;            const            dataURL            =            sail.            toDataURL            (            'image/png'            )            ;            render            dataURL;            }            export            {            upload            }                  

Came beyond this solution in this Stackoverflow post. Pretty useful. My online demo is using this service.

Basically, what the lawmaking practise is read the source, draw it in canvass, and salvage it as data url with the sheet toDataURL role. Acquire more nigh canvass here.

Now you can swap the real service with the fake one.

                      <            !            --            App.vue            --            >            ...            <            !            --            Javascript            --            >            <script>            // bandy as you need            import            {            upload            }            from            './file-upload.fake.service'            ;            // simulated service            // import { upload } from './file-upload.service';   // real service            <            /script>            ...                  

Done! Stop your backend API, refresh your browser, you should run across our app is still working, calling fake service instead.

Bonus: Delay Your Promises

Sometimes, you may want to delay the promises to see the country changes. In our case, the file upload may consummate too fast. Let's write a helper part for that.

                      // utils.js            // utils to delay hope            function            await            (            ms            )            {            render            (            ten            )            =>            {            return            new            Promise            (            resolve            =>            setTimeout            (            (            )            =>            resolve            (10)            ,            ms)            )            ;            }            ;            }            export            {            wait            }                  

Then, you tin can apply information technology in your component

                      <            !            --            App.vue            --            >            ...            <            !            --            Javascript            --            >            <script>            import            {            await            }            from            './utils'            ;            ...            salve            (            formData            )            {            ...            .            upload            (formData)            .            then            (            wait            (            1500            )            )            // DEV ONLY: wait for one.5s                        .            so            (            x            =>            {            this            .uploadedFiles            =            [            ]            .            concat            (10)            ;            this            .currentStatus            =            STATUS_SUCCESS            ;            }            )            ...            }            ,            <            /script>                  

Conclusion

That's information technology. This is how you tin can handle file upload without using whatsoever tertiary political party libraries and plugins in Vue. It isn't that difficult right?

Happy coding!

The UI (Front-end)

  • Sourcecode: https://github.com/chybie/file-upload-vue
  • Demo: https://vue-file-upload-1126b.firebaseapp.com/

The API (Dorsum-end) Tutorials and Sourcode

  • File upload with Hapi.js: https://scotch.io/bar-talk/handling-file-uploads-with-hapi-js, or
  • File upload with Express + Multer: https://scotch.io/tutorials/express-file-uploads-with-multer, or
  • Switch to any deject solution of your selection (Amazon S3, Google Drive, etc).

strangewittappona.blogspot.com

Source: https://www.digitalocean.com/community/tutorials/how-to-handle-file-uploads-in-vue-2