Manual File Upload Implementation with Element Plus and Axios
Managing file uploads manually in Element Plus requires bypassing the default upload behavior of the el-upload component. By utilizing the http-request attribute and disabling automatic submission, developers can gain full control over the request lifecycle, including custom headers and progress tracking.
Component Configuration
To prevent the component from sending a request immediately after a file is selected, set :auto-upload="false". The http-request property is then used to define a custom function that will handle the networking logic when the upload is triggered.
<template>
<div class="upload-container">
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:http-request="processFileUpload"
:limit="1"
:on-exceed="handleLimitExceeded"
>
<template #trigger>
<el-button type="primary">Select Spreadsheet</el-button>
</template>
<el-button
class="submit-btn"
type="success"
@click="triggerUpload"
>
Upload to Server
</el-button>
<template #tip>
<div class="el-upload__tip">
Accepted formats: .xlsx (Max 1 file)
</div>
</template>
</el-upload>
</div>
</template>
Custom Upload Logic
When submit() is called on the upload reference, the function assigned to http-request receives an object containing the file data. This file must be wrapped in a FormData instance to be correctly interpreted by most backend multipart parsers.
Its critical to set the Content-Type header to multipart/form-data. While some Axios configurations might default to application/json, file uploads will fail without the correct boundary definition provided by the multipart type.
import axios from 'axios';
import { ElMessage } from 'element-plus';
export default {
methods: {
// Trigger the manual upload process
triggerUpload() {
this.$refs.uploadRef.submit();
},
// Custom handler invoked by el-upload
async processFileUpload(params) {
const formPayload = new FormData();
formPayload.append('attachment', params.file);
try {
const response = await axios.post('/api/v1/import/excel', formPayload, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
if (response.data.status === 'success') {
ElMessage.success('Data imported successfully');
this.$refs.uploadRef.clearFiles();
} else {
ElMessage.error(response.data.message || 'Import failed');
}
} catch (error) {
ElMessage.error('Network error occurred during upload');
console.error('Upload Error:', error);
}
},
handleLimitExceeded() {
ElMessage.warning('Please remove the existing file before selecting a new one');
}
}
};
Handling Request Interceptors
When using global Axios interceptors, Ensure that the Content-Type is not hardcoded to application/json for every request. If an interceptor overwrites the headers, the multipart boundary needed for file transmission may be lost.
If your global configuration is strict, you can verify the data type within the interceptor:
axios.interceptors.request.use(config => {
// Only set JSON if the data is not an instance of FormData
if (!(config.data instanceof FormData)) {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
}
return config;
});
This appproach ensures that the el-upload component remains flexible, allowing for pre-processing logic, custom authentication tokens, or specific API endpoints that differ from the default component behavior.