Switch Branding In Your Angular Project
February 7, 2022Buddy Coding And Talking It Through
February 16, 2022
Many times in the past I’ve spent countless hours trying to figure out how to send an image or a text file to my backend with other data such as a custom name, a description or caption. Every time the common answer that pops up is to use a package like FS to achieve this however, not all frameworks allow Access to such packages, VueJS being one of the few frameworks that don’t allow access to the File System module.
So here is a simple solution that might work for you if you’re sitting with the same issue.
Lets create a simple component on our front-end in view called AddFile.vue
<template> <div> <input type="file" @change="fileChange" placeholder="Select File to upload…"/> <input type="text" v-model="fileName" placeholder="Custom filename…"/> <input type="textarea" v-model="fileDesc" rows="4” placeholder="Custom filename…"/> <embed name="plugin" :src="preview" type="application/pdf"> <button @click="submitFile">Submit</button> </div> </template> <script> export default { data(){ return{ selectedFile:null, description:null, fileName:null, preview:null, } }, methods:{ fileChange(event){}, async submitFile(){}, } } </script>
As you can see we have:
- an input field for the file type,
- A field to customise the filename once we submit
- A text area for the additional file description
- an embed field in order to view a preview of the file that has been selected
- and the submit button
fileChange function
In your component’s methods we’ll add the following code inside the fileChange function to store the file into the selectedFile variable.
var files = event.target.files || event.dataTransfer.files; if (!files.length) return; this.selectedFile = files[0];
We can then retrieve the filename from the selectedFile variable as well as the preview data within the same fileChange function.
this.fileName = this.selectedFile.name; this.preview = URL.createObjectURL(this.selectedFile)
Now that we have the file data, all that needs to be done is converting it to a format that can be sent over axios.
async toBase64(file) { return await new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = error => reject(error); }); },
We can start by adding this toBase64 function to our component’s methods
This returns the data that was in the file as a base64 string that we can then send via axios as a regular string in a JSON object.
submitFile
In the submitFile function that will be triggered by the Submit button,we add the following line of code:
let file = await this.toBase64(this.selectedFile);
This will call send the file to the function we wrote previously and that’s left to be done in the submitFile function is to send the data via axios to whichever endpoint needs it.
let postData={ fileData:file, fileName:this.fileName, description:this.description }; axios.post(`${url}`, postData, {headers:{'Content-Type':'application/x-www-form-urlencoded'}})
From here onwards we can decode the data on the backend again or on the front-end using the following snippet of code:
async dataURLtoFile(dataurl, filename) { return await new Promise((resolve, reject) => { try{ var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } resolve( new File([u8arr], filename, {type:mime})) }catch(e){ reject(e); } }) },
This will create a file using the file data that we sent through all that needs to be done is the file and fileName parameters need to be passed to the dataurl and filename parameters of the function respectively.