UZ - generic file uploading component
TL;DR
git clone https://github.com/js29a/uz.git
or
grab source:/uz/src/UploadZone.vue and source:/uz/src/UploadTest.vue
demo is available at https://vite.js29a.usermd.net/#/0
Aim of this article
In this article I'm about to demonstrate how to create and use generic file uploader component. You can use it not only with bare Vue-3 but also with Quasar, Vuetify or other Vue-3 toolkit. This article describes only browser-side concerns. You need to provide server side by you own.
The repository is also mirrored on GitHub.
Prerequisites
To use code covered by this wiki page you need to have following skills:
- basic Vue-3 knowledge (especially SFC with composition API),
- basic knowledge of TypeScript,
- very basic POST knowledge,
- rudimental knowlegde of jQuery
ajax
command.
Black-hole PHP POST acceptor script provided for faster setup: source:/uz/php/upload.php.
General info
Described component is based on a simple state machine. It has no UI by itself so you need to provide some UI on your own. To accomplish this not only component instantation is needed but there is also need to fill its slots. The component has several config options from which actually only one needs to be provided (i.e. target upload URL). Other options control component behavior but they will be explained later. After providing target upload URL there is need to fill component slots by your own UI. Here I will describe generic browser UI only. If you are familiar with e.g. Quasar you can implement the UI on your own.
In case of doubt please refer to source:/uz/src/UploadTest.vue file. It's complex because it demonstrates all the features. You'll probably use only some of them. Feel free to experiment.
Basic component usage
The first thing you need to do is to import the component and create an instance of it. Place the following line in your code - be careful to specifiy correct relative component path:
import UploadZone from './UploadZone.vue';
Then at your template code instantiate it. You will have to specify correct target upload URL. Endpoint specified here should handle POST requests.
<component :is='UploadZone' target='http://...'> </component>
As you see nothing will appear in browser. Why? You need to provide some UI. To remain generic the component has no UI by itself. This allows it to be extremely flexible. You need to use slots and provide some CSS styles. To remain concise this step is demonstrated in the repository (source:/uz/src/UploadTest.vue). After creating the UI and navigating to proper URL you should see the uploader.
In general there are two control options - using slots or to mix slots with control outside of the component. File source:/uz/src/UploadTest.vue demonstrates both of them.
Component properties
target
Destination URL. It should handle POST requests. Mandatory.
max-jobs
Maximum number of concurrent jobs. Optional. Defaults to 3.
auto-start
Start automatically after adding files, i.e. without wait to add more files. Optional. Defaults to false.
auto-reset
Automatically back to idle state after uploading given files. Optional. Defaults to false.
keep-going
Do not abort on error(s) - upload all files that can be uploaded. Optional. Defaults to false.
Slots
Common slot properties
abort
- callback function for aborting upload,current
- files that are currently uploaded,error
- error value - raw jQuery response,errors
- error vector, used when keep-going is set,pick
- callback that launches standard file picker,progress
- vector of results of files upload - parsed POST response,queue
- vector of files that are waiting for upload,reset
- callback function that resets component to idle state,result
- vector of parsed POST responses,start
- callback function that starts file uploading.
Provided slots
slot name | props | when used |
---|---|---|
idle | pick | nothing has to be done |
hover | (no props) | component is hovered with files - drop is possible |
wait | start, reset, queue | ready for upload |
uploading | progress, current, queue, errors, abort | upload is pending |
done | results, reset | upload is done |
error | error, reset | an error occured |
aborted | result, reset | upload has been aborted |
with-errors | result, errors, reset | upload completed with errors |
Exposed items
item | purpose | kind | |
---|---|---|---|
pick | launches standard file picker | callback | no args |
reset | resets to idle state | callback | no args |
start | begin files upload | callback | no args |
abort | abort pending files upload | callback | no args |
can_pick | is file picking allowed? | computed | boolean |
can_start | is upload start allowed? | computed | boolean |
can_abort | is upload abort allowed? | computed | boolean |
can_reset | is component reset allowed? | computed | boolean |
Emitted events
Component state events
update:canPick(flag: boolean)
- is file picking allowed,update:canReset(flag: boolean)
- is component reset allowed,update:canStart(flag: boolean)
- is upload start allowed,update:canAbort(flag: boolean)
- is upload abort allowed.
Other events
(to be written)
Other things
This component is implemented using Finite State Machine (Moore type) technique. It has eight states (idle, hover, wait, uploading, done, error, with_errors and aborted). It uses jQuery as underlying layer because it is the most common way to do REST requests. Rationale to implement it was need of specifying how many files could be uploaded at one time. The keynote was to not implement UI inside the component but relying to do such thing by user of this component.
Conclusion
The aim was rather to demonstrate some idea than to create universal piece of code. The idea was to demonstrate how to separate totally underlying controller layer from the UI. I hope this idea could be useful for someone.
Thanks for reading!

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.