I'm currently trying to create a small loading bar for when I select a file to upload in my form but I'm really struggling to make sense out of it. Most examples I find online show an upload loading example when we hit a button to 'upload' because it comes with an xmlhttprequest or similar, but in my case, I want to show the loading progress right when I select the file before I hit the button that sends the form. Therefore once I add the file to my input a loading percentage should appear. I'd really appreciate if someone could give an indication as to what needs to be done here.
FileUpload.vue - file upload input component
<div class="container">
<!--UPLOAD-->
<h3 class="form-input-title">{{labelText}}</h3>
<div class="dropbox">
<img src="../../assets/img/icon/curr/ic_download.svg"
class="download-icon"
alt="download icon"/>
<input :name="fieldName"
:accept="accept"
@change="loadFile($event)"
type="file"
class="input-file">
<p v-if="!isLoading && !isSuccess">{{text}}</p>
<p v-if="isLoading">Uploading files... {{uploadLoadPercentage}}</p>
<p v-if="isSuccess">{{fileName}}</p>
</div>
</div>
<script>
import {ref, watch} from '@vue/composition-api';
import Validator from "@/utils/yo-validator/YoValidator";
export default {
name: 'FileUpload',
setup(props) {
/** validator returned error messages **/
const {errorMessages, validateFieldByData, setFieldData} = Validator.register(props);
/** watch api error text from parent **/
const apiError = ref('');
watch(() => props.apiErrorText, (newVal) => {
apiError.value = newVal.trim();
});
const isLoading = ref(false);
const isSuccess = ref(false);
const uploadFailed = ref(false);
let uploadLoadPercentage = ref(0);
const fileName = ref('');
/** watch input in the template **/
const loadFile = async (event) => {
// TODO: File loading > When the file is selected, check how long the file (in bytes) takes to upload
// If the loading is successful proceed without any errors
// validate the image
validateFieldByData(event.target.files);
// define data
const data = props.isMultiple ? event.target.files : event.target.files[0];
// set the name of the file that has been uploaded.
fileName.value = event.target.files[0].name;
// Once loading and validation is completed, save the data
saveFile(data);
};
const saveFile = (data) => {
// Once saveFile is triggered, the upload value will be successful.
isSuccess.value = true;
// update form data
setFieldData(data);
// call the parent if needed
updateParent(data);
}
// update parent component
const updateParent = (data) => {
if (props.callback) {
props.callback(data);
}
};
const clearFile = (event) => {
// clear the value to trigger change event for uploading the same image
event.target.value = null;
};
return {
errorMessages,
apiError,
loadFile,
clearFile,
isLoading,
isSuccess,
uploadFailed,
fileName,
uploadLoadPercentage
}
}
}
</script>
First of all, progress for the file upload has to be tracked when you upload it to some server or to some storage space, normally you make a POST or PUT request, with axios, for example, which has a onUploadProgress
callback, with which you can upload your progress tracker, I will not go into detail here, since there are countless examples for this, like: The answer to this SO question , which details this nicely.
If you are in a special case, like not sending this through a simple HTTP request, but through something like firebase, they have builtin tools for this as well, but if you give more detail maybe i would be able to help you more in depth with your problem :D
UPDATE: Okay, sorry, my applogies, I totally misunderstood, what you needed:
< script > import { ref } from 'vue'; export default { setup() { const reader = new FileReader(); const fileUrl = ref(null); const totalSize = ref(0); const currentProgress = ref('0%'); function handleEvent(event) { if (['loadend', 'load'].includes(event.type)) { console.log('finished loading file'); currentProgress.value = 'Finished loading file'; fileUrl.value = reader.result; } if (event.type === 'progress') { currentProgress.value = `${(event.loaded / totalSize.value).toFixed(2) * 100}%`; console.log('Progress: ', currentProgress.value); console.log('Bytes transferred: ', event.loaded, 'bytes'); } if (event.type === 'loadstart') { totalSize.value = event.total; } } function addListeners(reader) { reader.addEventListener('loadstart', handleEvent); reader.addEventListener('load', handleEvent); reader.addEventListener('loadend', handleEvent); reader.addEventListener('progress', handleEvent); reader.addEventListener('error', handleEvent); reader.addEventListener('abort', handleEvent); //dont do this, make diffrent functions for every //event listener please, your code's readability will be 100% better, //i am on a bus rn, but will make it prettier later :D } function handleSelected(e) { console.log(e); const selectedFile = e.target.files[0]; if (selectedFile) { addListeners(reader); reader.readAsDataURL(selectedFile); } } return { handleSelected, fileUrl, currentProgress }; } }; < /script>
<template> <div> <div> <label for="img">Choose an image:</label> <input type="file" id="img" name="img" accept="image/*" @change="handleSelected" /> </div> <img v-if="fileUrl" :src="fileUrl" class="preview" height="200" alt="Image preview..." /> <div> <span>Progress: {{ currentProgress }}</span> </div> </div> </template>
Just make a Reader
object, which is there to handle these types of situations, and listen for the events emitted by it. Hope this helps, if you have any more questions, please ask :D And this is the output to the console, you can use this data to display on the UI as well:
NOTE: In my opinion for images you dont need this progress indicator, since they dont take a long time to upload and will show 100% for most of images(the console output is for a file that is 500mb large), but if you include the http request to upload the file here, then i think it would be ok, if you want to upload regular files, than this is expected and needed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.