Vue Js Undefined on File Upload Event

Introduction

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

We volition and then upload the selected images and display them accordingly. We will also learn to filter the upload file type, for instance, nosotros simply let images, do non allow file type like 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 two parts: the UI (front end-end) and the API (back-terminate). Nosotros will be using VueJs to handle the UI part. We demand a backend application to accept the uploaded files. Y'all may follow the backend tutorials or download and run either one of these server side awarding 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/limited-file-uploads-with-multer, or
  • Switch to any deject solution of your choice (Amazon S3, Google Drive, etc).

Nosotros will be using File upload with Hapi.js as our backend throughout this manufactures. We will also acquire the tricks to enable simulated upload on the front end-end.

Setup Project with Vue-Cli

Nosotros will be 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-unproblematic file-upload-vue                  

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

File Upload Component

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

                      <!-- App.vue -->            <!-- HTML Template -->                                          <template              >                                                      <div              id                              =                "app"                            >                                                      <div              course                              =                "container"                            >                        <!--UPLOAD-->                                          <grade              enctype                              =                "multipart/form-data"                            novalidate              v-if                              =                "isInitial || isSaving"                            >                                                      <h1              >            Upload images                              </h1              >                                                      <div              course                              =                "dropbox"                            >                                                      <input              type                              =                "file"                            multiple              :name                              =                "uploadFieldName"                            :disabled                              =                "isSaving"                            @change                              =                "filesChange($event.target.proper noun, $event.target.files); fileCount = $effect.target.files.length"                            accept                              =                "image/*"                            class                              =                "input-file"                            >                                                      <p              five-if                              =                "isInitial"                            >                        Drag your file(s) here to brainstorm                              <br              >                        or click to browse                                          </p              >                                                      <p              5-if                              =                "isSaving"                            >                        Uploading {{ fileCount }} files...                                          </p              >                                                      </div              >                                                      </form              >                                                      </div              >                                                      </template              >                        <!-- Javascript -->                                          <script              >                                                                                                          </script              >                        <!-- SASS styling -->                                          <fashion              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 course.
  3. The form aspect enctype="multipart/grade-data" is important. To enable file upload, this attribute must exist set. Larn more than nearly enctype hither.
  4. We have a file input <input blazon="file" /> to accept file upload. The belongings multiple betoken it's permit multiple file upload. Remove information technology for unmarried file upload.
  5. We will handle the file input change event. Whenever the file input change (someone drib or select files), we will trigger the filesChange role and pass in the command proper name and selected files $event.target.files, and then upload to server.
  6. We limit the file input to accept images only with the attribute accept="image/*".
  7. The file input volition exist disabled during upload, so user tin only drop / select files once more afterwards upload complete.
  8. Nosotros capture the fileCount of the when file changes. Nosotros utilize the fileCount variable in displaying number of files uploading Uploading {{ fileCount }} files....

Style our File Upload Component

Now, that's the interesting part. Currently, our component wait like this:

File upload component without styling

Nosotros need to transform it to look like this:

File upload component with styling

Let'due south mode it!

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

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

Notes:-

  1. We make the file input invisible by applying opacity: 0 style. This doesn't hide the file input, information technology just make it invisible.
  2. Then, we style the file input parent element, the dropbox css grade. We get in wait like a drop file zone surround with dash.
  3. Then, we align the text within 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            =            ane            ,            STATUS_SUCCESS            =            2            ,            STATUS_FAILED            =            3            ;            consign            default            {            proper noun            :            'app'            ,            information            (            )            {            return            {            uploadedFiles            :            [            ]            ,            uploadError            :            null            ,            currentStatus            :            null            ,            uploadFieldName            :            'photos'            }            }            ,            computed            :            {            isInitial            (            )            {            return            this            .currentStatus            ===            STATUS_INITIAL            ;            }            ,            isSaving            (            )            {            render            this            .currentStatus            ===            STATUS_SAVING            ;            }            ,            isSuccess            (            )            {            return            this            .currentStatus            ===            STATUS_SUCCESS            ;            }            ,            isFailed            (            )            {            return            this            .currentStatus            ===            STATUS_FAILED            ;            }            }            ,            methods            :            {            reset            (            )            {            // reset course to initial state            this            .currentStatus            =            STATUS_INITIAL            ;            this            .uploadedFiles            =            [            ]            ;            this            .uploadError            =            naught            ;            }            ,            save            (            formData            )            {            // upload data to the server            this            .currentStatus            =            STATUS_SAVING            ;            upload            (formData)            .            and so            (            10            =>            {            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            ;            // suspend the files to FormData            Array            .            from            (            Assortment            (fileList.length)            .            keys            (            )            )            .            map            (            10            =>            {            formData.            append            (fieldName,            fileList[x]            ,            fileList[x]            .name)            ;            }            )            ;            // relieve it            this            .            salvage            (formData)            ;            }            }            ,            mounted            (            )            {            this            .            reset            (            )            ;            }            ,            }            <            /script>                  

Notes:-

  1. Our component will have a few statuses: STATUS_INITIAL, STATUS_SAVING, STATUS_SUCCESS, STATUS_FAILED, the variable name is pretty expressive themselves.
  2. Later, we will telephone call the Hapi.js file upload API to upload images, the API accept a field call photos. That'due south 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. It let us to access the list of files selected with the <input type="file"> element. Learn more [here]((https://programmer.mozilla.org/en/docs/Web/API/FileList).
  4. We then create a new FormData, and append all our photos files to it. FormData interface provides a mode to easily construct a prepare of cardinal/value pairs representing form fields and their values. Learn more here.
  5. The salve role will call our file upload service (hang on, nosotros volition create the service next!). Nosotros also set the status according to the event.
  6. mount() is the vue component life cycle hook. During that point, we will set our component condition to initial land.

File Upload Service

Let's continue to create our service. We will exist using axios to brand HTTP calls.

Install axios

                      # install axios            npm            install            axios --save                  

Service

                      // file-upload.service.js            import            *            as            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            =>            x.data)            // add url field            .            then            (            10            =>            x.            map            (            img            =>            Object.            assign            (            {            }            ,            img,            {            url            :                          `                              ${                BASE_URL                }                            /images/                              ${img.id}                            `                        }            )            )            )            ;            }            export            {            upload            }                  

Nothing much, the code is pretty expressive itself. We upload the files, expect for the issue, map it accordingly.

You may run the application at present with npm run dev command. Try uploading a couple of images, and information technology'south working! (Remember to starting time your backend server)

Display Success and Failed Upshot

We can upload the files successfully at present. Nevertheless, in that location'south no indication in UI. Let's 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(due south) successfully.                              </h2              >                                                      <p              >                                                      <a              href                              =                "javascript:void(0)"                            @click                              =                "reset()"                            >            Upload again                              </a              >                                                      </p              >                                                      <ul              class                              =                "list-unstyled"                            >                                                      <li              five-for                              =                "item in uploadedFiles"                            >                                                      <img              :src                              =                "item.url"                            class                              =                "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()"                            >            Effort once more                              </a              >                                                      </p              >                                                      <pre              >            {{ uploadError }}                              </pre              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </template              >                              

Notes:-

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

Fake the Upload in Forepart-end

If y'all are lazy to start the back-cease awarding (Hapi, Express, etc) to handle file upload. Here is a simulated service to supplant the file upload service.

                      // file-upload.false.service.js            role            upload            (            formData            )            {            const            photos            =            formData.            getAll            (            'photos'            )            ;            const            promises            =            photos.            map            (            (            10            )            =>            getImage            (x)            .            then            (            img            =>            (            {            id            :            img,            originalName            :            x.proper noun,            fileName            :            x.name,            url            :            img            }            )            )            )            ;            return            Promise.            all            (promises)            ;            }            function            getImage            (            file            )            {            return            new            Promise            (            (            resolve,              reject            )            =>            {            const            fReader            =            new            FileReader            (            )            ;            const            img            =            document.            createElement            (            'img'            )            ;            fReader.            onload            =            (            )            =>            {            img.src            =            fReader.result;            resolve            (            getBase64Image            (img)            )            ;            }            fReader.            readAsDataURL            (file)            ;            }            )            }            function            getBase64Image            (            img            )            {            const            canvas            =            certificate.            createElement            (            'canvas'            )            ;            canvas.width            =            img.width;            sail.height            =            img.peak;            const            ctx            =            sheet.            getContext            (            'second'            )            ;            ctx.            drawImage            (img,            0            ,            0            )            ;            const            dataURL            =            canvas.            toDataURL            (            'image/png'            )            ;            render            dataURL;            }            export            {            upload            }                  

Came across this solution in this Stackoverflow postal service. Pretty useful. My online demo is using this service.

Basically, what the lawmaking practise is read the source, draw it in canvas, and save information technology every bit data url with the canvas toDataURL function. Learn more about canvas here.

Now you tin can bandy the real service with the fake one.

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

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

Bonus: Delay Your Promises

Sometimes, you may desire to delay the promises to see the state changes. In our case, the file upload may complete too fast. Let'southward write a helper function for that.

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

Then, you can utilise it in your component

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

Conclusion

That's it. This is how you lot tin handle file upload without using whatever tertiary party libraries and plugins in Vue. Information technology isn't that hard right?

Happy coding!

The UI (Forepart-cease)

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

The API (Back-cease) Tutorials and Sourcode

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

russellpossiounds58.blogspot.com

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

Related Posts

0 Response to "Vue Js Undefined on File Upload Event"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel