File Uploads
Learn how to upload files with Vueform.
Vueform's file upload can be configured in many ways in order to achieve different upload flows:
- Upload temporary files when the user selects them and only persist on form submit without having send over all the files again.
- Upload files instantly and have them persist after the user selects them and issue a remove call to the backend if they choose to remove them later.
- Upload files on form submit and have them sent along with form data.
Uploading Files
By default Vueform's FileElement
will issue a request to upload-temp-endpoint
when the user selects a file:
<FileElement upload-temp-endpoint="/store-temp-files" />
Disabling Auto-Uploading
To disable issuing a request instantly on file select, we can set auto
to false
:
<FileElement
upload-temp-endpoint="/store-temp-files"
:auto="false"
/>
In this case the user will have to press an Upload
button to upload files. If files are not uploaded by the time the form is submitted, they will be force uploaded to their endpoints in separate request(s) during prepare hook, before form data is sent.
Upload Request
The backend receives the following payload on submitting files to the endpoint:
{
file: '(binary)', // file binary
formKey: '...', // the form-key prop defined for `Vueform`
path: 'file', // the full path of the file element
}
Upload Response
After storing the file temporarily on our backend, the backend has to return a JSON in the following format:
const responseBody = {
tmp: 'y8wre123.pdf', // temp file name
originalName: 'contract.pdf', // the original file name
}
Once we receive the response from the backend the response body will be set as element value which will be sent as the file value when the form is submitted. It can be used to identify the temp file and make it persist when the form is submitted.
Skipping Temporary Upload State
If we want to skip the temporary uploaded file state, the backend can return the final filename as a string
:
const responseBody = 'final-file.pdf'
Changing Upload Request Method
By default, file upload requests are using POST
method, which can be changed by providing an object for upload-temp-endpoint
prop:
<FileElement :upload-temp-endpoint="{
url: '/user/temp-files',
method: 'PATCH',
}" />
Custom Upload Handling
We can also define an async function
instead of a string
endpoint for upload-temp-endpoint
:
<FileElement :upload-temp-endpoint="async (value, el$) => {
const response = await el$.$vueform.services.axios.request({
url: 'https://my-image-server.com/api/upload-temp',
method: 'POST',
data: el$.form$.convertFormData({
file: value,
}),
onUploadProgress: (e) => {
el$.progress = Math.round((e.loaded * 100) / e.total)
},
cancelToken: el$.$vueform.services.axios.CancelToken.source().token,
}) // errors are handled automatically
return response.data
}" />
Global Upload Endpoint Config
When upload-temp-endpoint
is not specified, its config value will be used from vueform.config.js
. We can use this to set the endpoint globally:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
uploadTempFile: {
url: '/vueform/file/upload-temp',
method: 'POST',
},
// or
uploadTempFile: async (value, el$) => {
// ...
}
}
})
Adding Params to Requests
We can add params to our request with params
when submitting to upload-temp-endpoint
:
<FileElement upload-temp-endpoint="/store-temp-files" :params="{
foo: 'bar',
}" />
The backend will receive:
{
file: '(binary)', // file binary
formKey: '...', // the form-key prop defined for `Vueform`
path: 'file', // the full path of the file element
foo: 'bar', // our custom param
}
Send Files on Form Submit Only
If we don't want to have separate requests to upload files, but send them along with other form data upon submit, we can simply set upload-temp-endpoint
to false
:
<FileElement :upload-temp-endpoint="false" />
We can also disable separate file upload requests on a config level:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
uploadTempFile: false
}
})
Restrict Accepted File Types
Accepted file types can be restricted by listing extensions or MIME types separated by comma:
<!-- Extensions -->
<FileElement accept=".jpg,.png,.gif" />
<!-- MIME Types -->
<FileElement accept="image/jpeg,image/png,image/gif" />
<!-- MIME Type Groups -->
<FileElement accept="image/*,video/*" />
Uploading Multiple Files
Multiple files can be uploaded using MultifileElement
:
<MultifileElement upload-temp-endpoint="/store-temp-files" />
When using MultifileElement
each files will be uploaded in separate requests to upload-temp-endpoint
.
Sorting Files
When uploading multiple files they can be sorted when sort: true
:
<MultifileElement sort view="image" />
File Validation
We can add validation rules to files restricting its size or even dimensions when uploading images:
<FileElement :rules="[
'min:1024', // min 1 MB file size
'max:4096', // max 4 MB file size
// image dimension constraints
'dimensions:min_width=100,min_height=100,max_witdh=1000,max_height=1000,ratio=2/3',
'dimensions:width=1024,height=768', // fixed size
]"
/>
When uploading multiple files the rules concerning one file instance should be passed via file
prop:
<MultifileElement
:rules="[ // APPLIES FOR MULTIFILE ELEMENT
'min:1', // min 1 file needs to be selected
'max:5', // max 5 files can be selected
]"
:file="{
rules: [ // APPLIES FOR SINGLE FILES
'min:1024', // min 1 MB file size
'max:4096', // max 4 MB file size
// ...
]
}"
/>
File Options
We can pass other file options eg. label
to single files when using MultifileElement
via file
prop:
<MultifileElement
:file="{
// ...
}"
/>
The MulfifileElement
behaves as a ListElement
containing FileElement
instances. With file
prop we can pass options to each FileElement
.
Drop Area
We can set drop: true
to display a drop area instead of file upload button for both FileElement
and MultifileElement
:
<MultifileElement drop />
Image Upload Diagram
Here's the full diagram of the image upload process:
File Preview
The FileElement
and MultifileElement
has different alternative views which can be used with view
prop:
default
<FileElement />
image
<FileElement view="image" />
gallery
<FileElement view="gallery" />
Clicking Files
The files are not clickable until they are persisted on our server (stage: 3
). Once they are persisted, their URL will be composed from the file value (eg. file.pdf
) prefixed with url
, which is /
by default.
If url
is not specified for our FileElement
the file will be opened in a new tab using /file.pdf
URL.
If url
is specified eg. https://cdn.domain.com/files/
the URL will become https://cdn.domain.com/files/file.pdf
:
<!-- Click URL: https://cdn.domain.com/files/file.pdf -->
<FileElement url="https://cdn.domain.com/files/" />
If the url
is false
the URL will be file.pdf
:
<!-- Click URL: file.pdf -->
<FileElement :url="false" />
If we want to turn off clickable links on files we can set clickable: false
:
<!-- The file won't be clickable -->
<FileElement :clickable="false" />
Here are some of the most common combinations for file click URL settings:
Filename | url | Click path |
---|---|---|
file.png | - (/ ) | /file.png |
file.png | false | file.png |
file.png | /files/ | /files/file.png |
file.png | https://cdn.com/ | https://cdn.com/file.png |
https://cdn.com/file.png | false | https://cdn.com/file.png |
Preview Images
Before images are persisted on the server (stage < 3
) the previews are converted to base64
and loaded to <img>
tag's src
attribute.
Once the files are uploaded (their value is a string
, stage: 3
) they will be loaded using their string value, prefixed with url
or previewUrl
prop.
If previewUrl
is not defined then url
will be used, which is also used for creating click URL.
The url
prop is /
by default, so if neither url
or previewUrl
is set and our FileElement
's value is file.png
it will be loaded from /file.png
.
If url
or previewUrl
is set to eg. https://cdn.domain.com/images/
the preview will be loaded from https://cdn.domain.com/images/file.png
.
If the url
is false
and previewUrl
is not defined, the file will not have a prefix (file.png
).
Here are some of the most common combinations for image preview settings:
Filename | url (click) | previewUrl | Click path | Preview path |
---|---|---|---|---|
file.png | - (/ ) | - | /file.png | /file.png |
file.png | false | - | file.png | file.png |
file.png | /files/ | - | /files/file.png | /files/file.png |
file.png | - (/ ) | /thumbnails/ | /file.png | /files/file.png |
file.png | /files/ | /thumbnails/ | /files/file.png | /thumbnails/file.png |
https://cdn.com/x.png | false | - | https://cdn.com/x.png | https://cdn.com/x.png |
Custom File Previews
If we need a custom file preview (eg. to render PDFs) we can create an alternative view.
Removing Files
When files are uploaded in a temporary state, meaning their value is an object containing tmp
and originalName
(stage: 2
) they will issue a request to remove-temp-endpoint
when removed:
<FileElement remove-temp-endpoint="/remove-temp-file">
When files are persisted, meaning their value is a string containing the filename (stage: 3
) they will issue a request to remove-endpoint
when removed.
<FileElement remove-endpoint="/remove-file">
Remove requests are only issued if the file is explicitly removed by the user and not when eg. resetting, clearing or updating form data.
Remove Request
The backend receives the following data when submitting to remove-temp-endpoint
or remove-endpoint
:
{
file: '(binary)', // file binary
formKey: '...', // the form-key prop defined for `Vueform`
path: 'file', // the full path of the file element
}
Remove Response
The response should have a 2XX
HTTP code and does not require any specific response. If the response is outside ot 2XX
the remove attempt will be considered failed and the file will not change its value.
Changing Remove Request Method
By default, file remove requests are using POST
method, which can be changed by providing an object for remove-temp-endpoint
or remove-endpoint
props:
<FileElement
:remove-temp-endpoint="{
url: '/user/temp-files',
method: 'DELETE',
}"
:remove-endpoint="{
url: '/user/files',
method: 'DELETE',
}"
/>
Custom Remove Handling
We can also define an async function
instead of a string
endpoint for :remove-temp-endpoint
and :remove-endpoint
:
<FileElement
:remove-temp-endpoint="async (value, el$) => {
await el$.$vueform.services.axios.request({
url: 'https://my-image-server.com/api/remove-temp',
method: 'POST',
data: el$.form$.convertFormData({
file: value,
}),
}) // errors are handled automatically
}"
:remove-endpoint="async (value, el$) => {
// same as above
}"
/>
Global Remove Endpoints Config
When :remove-temp-endpoint
and :remove-endpoint
are not specified, their config value will be used from vueform.config.js
. We can use this to set the endpoints globally:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
removeTempFile: {
url: '/vueform/file/remove-temp',
method: 'POST',
},
removeFile: {
url: '/vueform/file/remove',
method: 'POST',
},
// or
removeTempFile: async (value, el$) => {
// ...
},
removeFile: async (value, el$) => {
// ...
},
}
})
Adding Params to Requests
We can add params to our request with params
when submitting to remove-temp-endpoint
or remove-endpoint
:
<FileElement ... :params="{
foo: 'bar',
}" />
The backend will receive:
{
file: '(binary)', // file binary
formKey: '...', // the form-key prop defined for `Vueform`
path: 'file', // the full path of the file element
foo: 'bar', // our custom param
}
Soft Remove
If we don't want to issue separate requests when users delete files, we can set :soft-remove
to true
:
<FileElement soft-remove />
Alternatively, we can disable remove-temp-endpoint
or remove-endpoint
separately by setting them to false
:
<!-- Don't issue a request on removing temp file -->
<FileElement :remove-temp-endpoint="false" />
<!-- Don't issue a request on removing persisted file -->
<FileElement :remove-endpoint="false" />
We can also disable separate file remove requests on a config level:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
removeTempFile: false,
removeFile: false,
}
})
Loading Files
To load files to the form, we can simply set their filenames as values for FileElement
or MultifileElement
:
<template>
<Vueform ref="form$">
<FileElement name="file" />
<MultifileElement name="files" />
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
onMounted(() => {
form$.value.load({
file: 'filename.png',
files: [
'file1.pdf',
'file2.docx',
'file3.mp3',
]
})
})
</script>
<template>
<Vueform ref="form$">
<FileElement name="file" />
<MultifileElement name="files" />
</Vueform>
</template>
<script>
export default {
mounted() {
this.$refs.form$.load({
file: 'filename.png',
files: [
'file1.pdf',
'file2.docx',
'file3.mp3',
]
})
}
}
</script>
When images are loaded the previews will be composed of the loaded value for the file prefixed with url
or previewUrl
as we learned in Previewing Images section.