File Uploads Vue

To upload a single file in our application we will create a generic FileUpload component that can be reused. The component will accept props for the file types and API endpoint that the file will be uploaded to. In this example we will use the FileUpload component to upload a user's avatar to Digital Ocean Spaces using the Laravel API.

FileService

Create a FileService.js file in the services folder and add the following uploadFile method:

import * as API from "@/services/API";

export default {
  async uploadFile(payload) {
    await API.apiClient.post(payload.endpoint, payload.file);
  },
};

Create a FileUpload component that can be used to upload any single file. The full component can be found in the GitHub repo, let’s break it down.

File Input

The template will have an input field which has a type of file and the accept attribute value is a string that defines the file types, see further details here. The fileTypes are passed into the component as a prop.

<input type="file" :accept="fileTypes" @change="fileChange" />

Data Object

The data object just has three properties. The file property will hold the file object when it’s selected. The message and error properties hold the success and error messages that get displayed.

data() {
  return {
    file: null,
    message: null,
    error: null,
  };
}

Methods

The clearMessage method is simply used to clear any messages or errors each time a new file is uploaded.

clearMessage() {
  this.error = null;
  this.message = null;
}

The fileChange method runs every time a file is selected, and it sets the file data property to the event.target.files[0] which will be a File object.

fileChange(event) {
  this.clearMessage();
  this.file = event.target.files[0];
}

The uploadFile method will create a payload to pass through to the FileService. To send the file through in the correct format we need to new up an instance of the FormData object. The FormData object has an append method where the file is passed in. See more information how this works over on MDN. The payload also has an endpoint property which is used to accept the API endpoint that the file will be sent to. We do this so that the FileUpload component can be reusable for uploading different files to different API endpoints.

uploadFile() {
  const payload = {};
  const formData = new FormData();
  formData.append("file", this.file);
  payload.file = formData;
  payload.endpoint = this.endpoint;
  this.clearMessage();
  FileService.uploadFile(payload)
  .then(() => {
    this.message = "File uploaded.";
    this.$emit("fileUploaded");
  })
  .catch((error) => (this.error = getError(error)));
}

Notice in the then method on the FileService.uploadFile we emit an event called fileUploaded, this enables us to listen for when the file has been uploaded in the parent component. The listener provides other functionality, we will use it to update the users profile page without them needing to refresh the page.

With the FileUpload component built all that's left to do is add it into the User view we previously created.

<template>
  //...
  <FileUpload
    label="Upload Avatar"
    :fileTypes="['image/*']"
    endpoint="/users/auth/avatar"
    @fileUploaded="updateUser"
    class="p-5 bg-white border rounded shadow"
  />
</template>
<script>
  import FlashMessage from "@/components/FlashMessage";
  export default {
    //...
    components: {
      FlashMessage,
    },
    methods: {
      updateUser() {
        this.$store.dispatch("auth/getAuthUser");
      }
    }
  }
</script>

With this in place and the Laravel API functionality built, you should be able to login to your application and upload a file to your Digital Ocean Spaces account.