<template> <DocSectionText v-bind="$attrs"> <p>Uploader UI can be customized with templating.</p> </DocSectionText> <div class="card"> <FileUpload name="demo[]" url="./upload.php" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles"> <template #header="{ chooseCallback, uploadCallback, clearCallback, files }"> <div class="flex flex-wrap justify-content-between align-items-center flex-1 gap-2"> <div class="flex gap-2"> <Button @click="chooseCallback()" icon="pi pi-images" class="p-button-rounded"></Button> <Button @click="uploadEvent(uploadCallback)" icon="pi pi-cloud-upload" class="p-button-rounded p-button-success" :disabled="!files || files.length === 0"></Button> <Button @click="clearCallback()" icon="pi pi-times" class="p-button-rounded p-button-danger" :disabled="!files || files.length === 0"></Button> </div> <ProgressBar :value="totalSizePercent" :showValue="false" :class="['md:w-20rem h-1rem w-full md:ml-auto', { 'exceeded-progress-bar': totalSizePercent > 100 }]"> <span class="white-space-nowrap">{{ totalSize }}B / 1Mb</span> </ProgressBar> </div> </template> <template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }"> <div v-if="files.length > 0"> <h5>Pending</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Pending" severity="warning" /> <Button icon="pi pi-times" @click="onRemoveTemplatingFile(file, removeFileCallback, index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> <div v-if="uploadedFiles.length > 0"> <h5>Completed</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Completed" class="mt-3" severity="success" /> <Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> </template> <template #empty> <div class="flex align-items-center justify-content-center flex-column"> <i class="pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400" /> <p class="mt-4 mb-0">Drag and drop files to here to upload.</p> </div> </template> </FileUpload> </div> <DocSectionCode :code="code" /> </template> <script> export default { data() { return { files: [], totalSize: 0, totalSizePercent: 0, code: { basic: ` <FileUpload name="demo[]" url="./upload.php" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles"> <template #header="{ chooseCallback, uploadCallback, clearCallback, files }"> <div class="flex flex-wrap justify-content-between align-items-center flex-1 gap-2"> <div class="flex gap-2"> <Button @click="chooseCallback()" icon="pi pi-images" class="p-button-rounded"></Button> <Button @click="uploadEvent(uploadCallback)" icon="pi pi-cloud-upload" class="p-button-rounded p-button-success" :disabled="!files || files.length === 0"></Button> <Button @click="clearCallback()" icon="pi pi-times" class="p-button-rounded p-button-danger" :disabled="!files || files.length === 0"></Button> </div> <ProgressBar :value="totalSizePercent" :showValue="false" :class="['md:w-20rem h-1rem w-full md:ml-auto', { 'exceeded-progress-bar': totalSizePercent > 100 }]" ><span class="white-space-nowrap">{{ totalSize }}B / 1Mb</span></ProgressBar > </div> </template> <template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }"> <div v-if="files.length > 0"> <h5>Pending</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Pending" severity="warning" /> <Button icon="pi pi-times" @click="onRemoveTemplatingFile(file, removeFileCallback, index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> <div v-if="uploadedFiles.length > 0"> <h5>Completed</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Completed" class="mt-3" severity="success" /> <Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> </template> <template #empty> <div class="flex align-items-center justify-content-center flex-column"> <i class="pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400" /> <p class="mt-4 mb-0">Drag and drop files to here to upload.</p> </div> </template> </FileUpload>`, options: ` <template> <div class="card"> <Toast /> <FileUpload name="demo[]" url="./upload.php" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles"> <template #header="{ chooseCallback, uploadCallback, clearCallback, files }"> <div class="flex flex-wrap justify-content-between align-items-center flex-1 gap-2"> <div class="flex gap-2"> <Button @click="chooseCallback()" icon="pi pi-images" class="p-button-rounded"></Button> <Button @click="uploadEvent(uploadCallback)" icon="pi pi-cloud-upload" class="p-button-rounded p-button-success" :disabled="!files || files.length === 0"></Button> <Button @click="clearCallback()" icon="pi pi-times" class="p-button-rounded p-button-danger" :disabled="!files || files.length === 0"></Button> </div> <ProgressBar :value="totalSizePercent" :showValue="false" :class="['md:w-20rem h-1rem w-full md:ml-auto', { 'exceeded-progress-bar': totalSizePercent > 100 }]" ><span class="white-space-nowrap">{{ totalSize }}B / 1Mb</span></ProgressBar > </div> </template> <template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }"> <div v-if="files.length > 0"> <h5>Pending</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Pending" severity="warning" /> <Button icon="pi pi-times" @click="onRemoveTemplatingFile(file, removeFileCallback, index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> <div v-if="uploadedFiles.length > 0"> <h5>Completed</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Completed" class="mt-3" severity="success" /> <Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> </template> <template #empty> <div class="flex align-items-center justify-content-center flex-column"> <i class="pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400" /> <p class="mt-4 mb-0">Drag and drop files to here to upload.</p> </div> </template> </FileUpload> </div> </template> <script> export default { data() { return { files: [], totalSize: 0, totalSizePercent: 0, }; }, methods: { onRemoveTemplatingFile(file, removeFileCallback, index) { removeFileCallback(index); this.totalSize -= parseInt(this.formatSize(file.size)); this.totalSizePercent = this.totalSize / 10; }, onClearTemplatingUpload(clear) { clear(); this.totalSize = 0; this.totalSizePercent = 0; }, onSelectedFiles(event) { this.files = event.files; this.files.forEach((file) => { this.totalSize += parseInt(this.formatSize(file.size)); }); }, uploadEvent(callback) { this.totalSizePercent = this.totalSize / 10; callback(); }, onTemplatedUpload() { this.$toast.add({ severity: 'info', summary: 'Success', detail: 'File Uploaded', life: 3000 }); }, formatSize(bytes) { if (bytes === 0) { return '0 B'; } let k = 1000, dm = 3, sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } } }; <\/script>`, composition: ` <template> <div class="card"> <Toast /> <FileUpload name="demo[]" url="./upload.php" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles"> <template #header="{ chooseCallback, uploadCallback, clearCallback, files }"> <div class="flex flex-wrap justify-content-between align-items-center flex-1 gap-2"> <div class="flex gap-2"> <Button @click="chooseCallback()" icon="pi pi-images" class="p-button-rounded"></Button> <Button @click="uploadEvent(uploadCallback)" icon="pi pi-cloud-upload" class="p-button-rounded p-button-success" :disabled="!files || files.length === 0"></Button> <Button @click="clearCallback()" icon="pi pi-times" class="p-button-rounded p-button-danger" :disabled="!files || files.length === 0"></Button> </div> <ProgressBar :value="totalSizePercent" :showValue="false" :class="['md:w-20rem h-1rem w-full md:ml-auto', { 'exceeded-progress-bar': totalSizePercent > 100 }]" ><span class="white-space-nowrap">{{ totalSize }}B / 1Mb</span></ProgressBar > </div> </template> <template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }"> <div v-if="files.length > 0"> <h5>Pending</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Pending" severity="warning" /> <Button icon="pi pi-times" @click="onRemoveTemplatingFile(file, removeFileCallback, index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> <div v-if="uploadedFiles.length > 0"> <h5>Completed</h5> <div class="flex flex-wrap p-0 sm:p-5 gap-5"> <div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="card m-0 px-6 flex flex-column border-1 surface-border align-items-center gap-3"> <div> <img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" class="shadow-2" /> </div> <span class="font-semibold">{{ file.name }}</span> <div>{{ formatSize(file.size) }}</div> <Badge value="Completed" class="mt-3" severity="success" /> <Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" class="p-button-outlined p-button-danger p-button-rounded" /> </div> </div> </div> </template> <template #empty> <div class="flex align-items-center justify-content-center flex-column"> <i class="pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400" /> <p class="mt-4 mb-0">Drag and drop files to here to upload.</p> </div> </template> </FileUpload> </div> </template> <script setup> import { useToast } from "primevue/usetoast"; const toast = useToast(); const totalSize = ref(0); const totalSizePercent = ref(0); const files = ref([]); const onRemoveTemplatingFile = (file, removeFileCallback, index) => { removeFileCallback(index); totalSize.value -= parseInt(formatSize(file.size)); totalSizePercent.value = totalSize.value / 10; }; const onClearTemplatingUpload = (clear) => { clear(); totalSize.value = 0; totalSizePercent.value = 0; }; const onSelectedFiles = (event) => { files.value = event.files; files.value.forEach((file) => { totalSize.value += parseInt(formatSize(file.size)); }); }; const uploadEvent = (callback) => { totalSizePercent.value = totalSize.value / 10; callback(); }; const onTemplatedUpload = () => { toast.add({ severity: "info", summary: "Success", detail: "File Uploaded", life: 3000 }); }; const formatSize = (bytes) => { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; <\/script>` } }; }, methods: { onRemoveTemplatingFile(file, removeFileCallback, index) { removeFileCallback(index); this.totalSize -= parseInt(this.formatSize(file.size)); this.totalSizePercent = this.totalSize / 10; }, onClearTemplatingUpload(clear) { clear(); this.totalSize = 0; this.totalSizePercent = 0; }, onSelectedFiles(event) { this.files = event.files; this.files.forEach((file) => { this.totalSize += parseInt(this.formatSize(file.size)); }); this.totalSizePercent = this.totalSize / 10; }, uploadEvent(callback) { callback(); }, onTemplatedUpload() { this.$toast.add({ severity: 'info', summary: 'Success', detail: 'File Uploaded', life: 3000 }); }, formatSize(bytes) { if (bytes === 0) { return '0 B'; } let k = 1000, dm = 3, sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } } }; </script>