Level 73
You most likely need to reset the file input after the upload.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hello guys, hope you are okay, I ma facing some issue with my code
<script setup>
import {defineProps, onMounted, ref, watch} from 'vue';
import axios from 'axios';
import {ArrowUpOnSquareIcon, TrashIcon} from "@heroicons/vue/24/solid";
const emit = defineEmits(['pendingUploads']);
let props = defineProps({
url: {
type: String,
Required: true,
},
maxSize: {
type: Number,
default: 5000000
},
acceptedTypes: {
type: Array,
default: () => ['image/png', 'image/jpeg', 'image/jpg'],
},
skipExistingFiles: {
type: Boolean,
default: false,
}
});
let files = ref([]);
let totalProgress = ref(0);
let uploadSpeed = ref(0);
let errorMessage = ref('');
let isDragOver = ref(false);
let displayError = ref(true);
let canUpload = ref(false);
let fileInput = ref(null);
let isUploading = ref(false);
let uploadedFileIds = ref([]);
const calculateTotalProgress = () => {
const totalCompleted = files.value.reduce((acc, file) => acc + (file.progress || 0), 0);
const validFiles = files.value.filter(file => !file.error);
totalProgress.value = validFiles.length ? totalCompleted / validFiles.length : 0;
};
const handleFiles = async (eventFiles) => {
files.value = [...files.value, ...[...eventFiles].map((file, index) => {
if (file.size > props.maxSize) {
file.errorMessage = 'File size exceeds the maximum limit.';
errorMessage.value = file.errorMessage;
file.error = true;
file.uuid = Math.random().toString(36).substring(7);
return file;
}
if (!props.acceptedTypes.includes(file.type)) {
file.errorMessage = 'File type not supported.';
errorMessage.value = file.errorMessage;
file.error = true;
return file;
}
file.previewUrl = URL.createObjectURL(file);
file.uploading = false;
file.progress = 0;
calculateTotalProgress();
return file;
})];
canUpload.value = true;
emit('pendingUploads', true);
};
const uploadFile = async (file) => {
const startTime = new Date().getTime();
file.uploading = true;
file.error = false;
const formData = new FormData();
formData.append('file', file);
file.progress = 0;
await axios.post(props.url, formData, {
onUploadProgress: progressEvent => {
file.progress = Number(((progressEvent.loaded / progressEvent.total * 100).toFixed(2)));
calculateTotalProgress();
const elapsedTime = new Date().getTime() - startTime;
uploadSpeed.value = ((progressEvent.loaded / (1024 * 1024)) / (elapsedTime / 1000)).toFixed(2);
}
})
.then((response) => {
file.uploading = false;
file.uploaded = true;
file.success = true;
file.id = response.data.id;
calculateTotalProgress();
uploadedFileIds.value.push(response.data.id);
console.log(uploadedFileIds.value);
})
.catch((error) => {
file.uploading = false;
file.error = true;
errorMessage.value = error.message;
calculateTotalProgress();
});
};
const dropHandler = (e) => {
e.preventDefault();
isDragOver.value = false;
const droppedFiles = e.dataTransfer.files;
handleFiles(droppedFiles);
e.target.value = null;
};
const dragOverHandler = (e) => {
e.preventDefault();
isDragOver.value = true;
};
const dragLeaveHandler = (e) => {
e.preventDefault();
isDragOver.value = false;
};
onMounted(() => emit('filesPending', false));
watch(files, () => {
if (!files.value.length) {
emit('pendingUploads', false);
}
});
const uploadFiles = async () => {
// Only upload if canUpload is true and not already uploading
if (canUpload.value && !isUploading.value) {
isUploading.value = true; // Set flag to indicate upload in progress
for (const file of files.value) {
if (!file.error) {
await uploadFile(file);
}
}
isUploading.value = false; // Reset flag when upload is complete
}
};
const deleteFile = (index) => {
files.value.splice(index, 1);
};
const deleteAllFiles = () => {
files.value = [];
canUpload.value = false;
};
const openFilePicker = () => {
if (fileInput.value) {
fileInput.value.click();
}
};
watch(errorMessage, () => {
setTimeout(() => {
displayError.value = false;
}, 5000);
});
</script>
<template>
<div class="w-1/2 justify-center flex-row mx-auto">
<transition name="slide-fade">
<div v-if="errorMessage && displayError"
class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 round mx-2 my-2"
role="alert">
<strong class="font-bold">Error! </strong>
<span class="block sm:inline">
{{ errorMessage }}
</span>
</div>
</transition>
<div
@drop="dropHandler"
@dragover="dragOverHandler"
@dragleave="dragLeaveHandler"
@click="openFilePicker"
:class="{'bg-gray-300': isDragOver}"
class="m-4 p-4 border-2 border-gray-300"
>
<div class="grid grid-cols-4 gap-4">
<div
v-for="(file, index) in files"
:key="index"
:data-file-name="file.name"
:class="{'bg-orange-500': file.error, 'bg-gray-100': !file.uploading && !file.error, 'border-red-600': file.error, 'border-gray-300': !file.error, 'border-b-fuchsia-950': file.success}"
class="grid grid-cols-1 m-2 p-2 border rounded-md items-center justify-between">
<img v-if="props.acceptedTypes.includes(file.type)"
:data-file-name="file.name"
:src="file.previewUrl" alt="Image preview"
class="h-auto w-full object-cover rounded"/>
<span class="self-center text-sm text-center mt-2 text-gray-500">
{{ file.name }}
</span>
<div class="flex items-center">
<progress :value="file.progress" max="100" class="w-full rounded-full"></progress>
<button @click="deleteFile(index)"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-1 rounded w-8 h-8 ml-2">
<TrashIcon class="h-5 w-5 inline-block"/>
</button>
</div>
</div>
</div>
</div>
<input type="file" multiple ref="fileInput" @change="handleFiles($event.target.files)" class="opacity-0">
<div class="flex m-2 p-2 items-center">
<span class="ml-2">Upload speed: {{ uploadSpeed }} MBps</span>
<button @click="uploadFiles"
:disabled="!canUpload"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
<ArrowUpOnSquareIcon class="h-5 w-5 inline-block"/>
</button>
<button @click="deleteAllFiles"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2">
<TrashIcon class="h-5 w-5 inline-block"/>
</button>
<progress :value="totalProgress" max="100" class="ml-2 w-full rounded-md"></progress>
</div>
</div>
</template>
<style scoped>
.bg-gray-300 {
background-color: #e5e7eb;
}
.w-full {
width: 100%;
}
.h-full {
height: 100%;
}
.opacity-0 {
opacity: 0;
}
:deep(.bg-orange-500) {
background-color: #FFA500;
}
</style>
upload works perfect, but after upload 2 files i will add new file and try upload again, All files will be upload again, i mean 2 old files and new one.
Please or to participate in this conversation.