Tuesday, 18 July, 2017 UTC


Summary

File and image uploads are a must-have feature for many non-trivial apps. Lucky for us, it’s easy to setup in Vue apps with vue-picture-input.
Check this post of ours if you're looking to create your own custom file selector input.
Installation
Install vue-picture-input via npm or Yarn:
$ npm install --save vue-picture-input # or: $ yarn add vue-picture-input
Usage
The vue-picture-input library allows for a variety of usages, and is very simple to use:
<template> <picture-input <!--Props go here--> ></picture-input> </template>
Here are a few props that we’re going to make use of:
  • ref: We’ll need this to access the base64 image string
  • width, height: Dictate the width and height of the component
  • accept: Used to restrict accepted file types
  • removable: Specifies whether the component can be reset or not
Additionally, the component emits the following events:
  • removed: emitted when picture is detached from component
  • changed: emitted when the selected picture is changed (ie. reselected)
Here’s what our code looks like for the file input:
index.vue
<picture-input ref="pictureInput" @change="onChanged" @remove="onRemoved" :width="500" :removable="true" removeButtonClass="ui red button" :height="500" accept="image/jpeg, image/png, image/gif" buttonClass="ui button primary" :customStrings="{ upload: '<h1>Upload it!</h1>', drag: 'Drag and drop your image here'}"> </picture-input> 

Let’s add a button that will allow us to upload the selected image to our backend.
It basically calls the attemptUpload method when clicked and has the disabled class binding. It’ll only be enabled if there’s a selected image:
<button @click="attemptUpload" v-bind:class="{ disabled: !image }"> Upload </button> 
Next, we’ll use Axios to make network requests. We’ll also leverage the Formdata API to create a sweet composition for posting image data:
upload.js
import axios from 'axios'; export default function (url, file, name = 'avatar') { if (typeof url !== 'string') { throw new TypeError(`Expected a string, got ${typeof url}`); } // You can add checks to ensure the url is valid, if you wish const formData = new FormData(); formData.append(name, file); const config = { headers: { 'content-type': 'multipart/form-data' } }; return axios.post(url, formData, config); }; 
The above code accepts a url as the first parameter and a file object as the second parameter then returns a promise. It also sets the header’s content-type to multipart/formdata so our backend API can tell what’s in the pipes.
We can therefore use the above code as so:
import FormDataPost from '/upload'; //... FormDataPost('http://localhost:8001/user/picture', image) .then(response=>{ console.log("Uploaded picture successfully"); }) .catch(err=>{ console.error(err); }); //... 
Here’s what our onChanged, onRemoved and attemptUpload methods look like:
//... methods: { onChanged() { console.log("New picture loaded"); if (this.$refs.pictureInput.file) { this.image = this.$refs.pictureInput.file; } else { console.log("Old browser. No support for Filereader API"); } }, onRemoved() { this.image = ''; }, attemptUpload() { if (this.image){ FormDataPost('http://localhost:8001/user/picture', this.image) .then(response=>{ if (response.data.success){ this.image = ''; console.log("Image uploaded successfully ✨"); } }) .catch(err=>{ console.error(err); }); } } } //... 
💪 Done! Our image upload is working on the frontend. Read-on for how to set this up on a Node.js backend using Express.