A few weeks back I wrote about accepting file uploads in a Node.js application that uses Hapi framework. This was a followup to an article I wrote titled, Upload Files to Node.js Using Angular. What if we wanted to use a different front-end framework instead of Angular?
We’re going to take a look at using FormData and Vue.js to upload files, such as images, to a remote web service. Either of the two web services that we’ve previously created, whether it be with Hapi or Express, will work for this example.
To make this example simple and easy to understand, we’re going to start with a brand new project. Using the Vue CLI, execute the following command:
vue init webpack upload-project
When prompted, just say no to everything including the question regarding the router component. It doesn’t matter if we use a standalone build setup or runtime-only.
After the project is created, execute the following:
cd upload-project
npm install
The above commands will install all the dependencies required for the scaffolded Vue.js project.
Because we’ll be using a remote web service, we’ll need to be able to make HTTP requests. If you haven’t already, check out an article I wrote previously titled, Consume Remote API Data via HTTP in a Vue.js Web Application. We’ll be using the axios library for this example. It can be installed by executing the following:
npm install axios --save
At this point we can start adding our application logic.
When we develop our application, we’re going to do everything in the project’s src/App.vue file. We won’t be focusing on any styling, but we will be working with HTML templates and scripts.
Open the project’s src/App.vue file and include the following <script>
block:
<script>
import axios from "axios";
export default {
name: 'app',
data() {
return {
files: new FormData()
}
},
methods: {
fileChange(fileList) {
this.files.append("file", fileList[0], fileList[0].name);
},
upload() {
axios({ method: "POST", "url": "http://localhost:3000", "data": this.files }).then(result => {
console.dir(result.data);
}, error => {
console.error(error);
});
}
}
}
</script>
With the HTML component for selecting files, we cannot directly bind a variable. For this reason, everything is going to be based on methods.
We will be sending FormData to our remote web service. When data is populated in our file explorer, we will be calling the fileChange
method, passing the file data. This data will be added as FormData. When we finally choose to upload our data, the upload
method will be called. The upload
method will do a POST request with the axios library.
The <template>
block that pairs in the src/App.vue file is quite simple. It looks like the following:
<template>
<div id="app">
<h1>Upload a File</h1>
<form enctype="multipart/form-data">
<input type="file" name="file" v-on:change="fileChange($event.target.files)" />
<input type="file" name="file" v-on:change="fileChange($event.target.files)" />
<button type="button" v-on:click="upload()">Upload</button>
</form>
</div>
</template>
In the above HTML, we have several <input>
components for files. If you think back to the Hapi with Node.js example, we are accepting multiple files in a single request. Each will trigger a change event and add the file information to our FormData.
When we want to upload, the button will trigger the upload
method via the v-on:click
event.
The complete code in our src/App.vue file for our project should look like the following:
<template>
<div id="app">
<h1>Upload a File</h1>
<form enctype="multipart/form-data">
<input type="file" name="file" v-on:change="fileChange($event.target.files)" />
<input type="file" name="file" v-on:change="fileChange($event.target.files)" />
<button type="button" v-on:click="upload()">Upload</button>
</form>
</div>
</template>
<script>
import axios from "axios";
export default {
name: 'app',
data() {
return {
files: new FormData()
}
},
methods: {
fileChange(fileList) {
this.files.append("file", fileList[0], fileList[0].name);
},
upload() {
axios({ method: "POST", "url": "http://localhost:3000", "data": this.files }).then(result => {
console.dir(result.data);
}, error => {
console.error(error);
});
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
If everything was done correctly in the Vue.js application and the backend application, you should see files on your server depending on what you’ve chosen to upload.
You just saw how to upload files to a remote web service via a Vue.js web application. By leveraging FormData and the change events, we can accomplish the job with minimal effort. In most applications that I build, there is an upload requirement, most typically for images, so this example works perfectly.
If you haven’t already, I highly recommend you check out my example regarding file uploads with Hapi and Node.js. If you’d prefer not to use Hapi, check out my example that uses Express.