Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 63 additions & 25 deletions djvue/static/vue/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ let djVueMixin = {
options: {},
nonFieldErrors: [],
actionURL: null,
uploadInProgress: {},
form: {},
files: {},
fileUploadURL: uploadURL
}
},
computed: {
canSubmit: function() {
return !this.submitInProgress && !Object.values(this.uploadInProgress).some(e => e === true)
}
},
mounted() {
axios.options(this.actionURL).then((response) => {
this.options = response.data.actions.POST
Expand Down Expand Up @@ -116,10 +122,40 @@ let djVueMixin = {
}
})
},
uploadFile(event, url, multiple=false) {
uploadFile(event, url, max_file_size, multiple=false) {
let formData = new FormData()
// save vue instance for being able to reference it later.
const vm = this
file_size = event.target.files[0].size
uploaded_files = []
if(this.files["files"]){
this.files["files"].forEach(key=> {
uploaded_files.push(key.filename)
})
}
if(uploaded_files.includes(event.target.files[0].name)){
this.$refs.form.setErrors({
files: [duplicate_file_msg]
});
return
}
let max_file_size_mb = Boolean(max_file_size) ? parseFloat(max_file_size) : 15;
if (file_size > 1024 * 1024 * max_file_size_mb) {
if(multiple){
this.$refs.form.setErrors({
[event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit]
});
}
else{
this.$refs.form.setErrors({
[event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit]
});
}
return;
}

Vue.set(vm.uploadInProgress, event.target.name, true)

// clear the errors
this.$refs.form.setErrors({[event.target.name]: []})

Expand All @@ -128,32 +164,34 @@ let djVueMixin = {

formData.append("file", event.target.files[0])
axios
.post(uploadURL, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then(({ data }) => {
// save details on the form data which will be sent to the server
if (multiple) {
let current_files = []
if (event.target.name in vm.files) {
current_files = vm.files[event.target.name]
}
current_files.push(data);
Vue.set(vm.files, event.target.name, current_files)

} else {
Vue.set(vm.files, event.target.name, data)
vm.$emit('uploadedFile', event)
.post(uploadURL, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then(({ data }) => {
// save details on the form data which will be sent to the server
if (multiple) {
let current_files = []
if (event.target.name in vm.files) {
current_files = vm.files[event.target.name]
}
current_files.push(data);
Vue.set(vm.files, event.target.name, current_files)

})
.catch((error) => {
// remove the file from the input
event.target.value = null
vm.error(error)
})
} else {
Vue.set(vm.files, event.target.name, data)

}

})
.catch((error) => {
// remove the file from the input
event.target.value = null
vm.error(error)
}).finally(() => {
Vue.set(vm.uploadInProgress, event.target.name, false)
})
},
},
}
8 changes: 7 additions & 1 deletion djvue/templates/vue/default/file.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% load i18n %}

<validation-provider name="{{ field.name }}"
{% if style.rules %} rules="{{ style.rules }}" {% endif %}
v-slot="{ errors, valid, invalid, touched }"
Expand All @@ -10,13 +12,17 @@
<div class="col-sm-10">
<input name="{{ field.name }}"
type="file"
:disabled="uploadInProgress.{{ field.name }}"
{% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %}
{% if field.value is not None %}value="{{ field.value }}"{% endif %}
{% if field.required %}required{% endif %}
@change="uploadFile($event, '{{ style.upload_url }}')"
@change="uploadFile($event, '{{ style.upload_url }}', '{{ style.max_file_size }}')"
:class="{'is-invalid': touched && invalid, 'is-valid': touched && valid && form.{{ field.name }}}"
>
<span class="help-block text-danger" v-for="error in errors" :key="error">{( error )}</span>
<span v-if="uploadInProgress.{{ field.name }}">
{% trans 'Uploading...' %}
</span>

{% if field.help_text %}
<span class="help-block">{{ field.help_text|safe }}</span>
Expand Down
8 changes: 7 additions & 1 deletion djvue/templates/vue/default/file_multiple.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% load i18n %}

<validation-provider name="{{ field.name }}"
{% if style.rules %} rules="{{ style.rules }}" {% endif %}
v-slot="{ errors, valid, invalid, touched }"
Expand All @@ -10,13 +12,17 @@
<div class="col-sm-10">
<input name="{{ field.name }}"
type="file" multiple
:disabled="uploadInProgress.{{ field.name }}"
{% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %}
{% if field.value is not None %}value="{{ field.value }}"{% endif %}
{% if field.required %}required{% endif %}
@change="uploadFile($event, '{{ style.upload_url }}', true)"
@change="uploadFile($event, '{{ style.upload_url }}', '{{ style.max_file_size }}', true)"
:class="{'is-invalid': touched && invalid, 'is-valid': touched && valid && form.{{ field.name }}}"
>
<span class="help-block text-danger" v-for="error in errors" :key="error">{( error )}</span>
<span class="help-block" v-if="uploadInProgress.{{ field.name }}">
{% trans 'Uploading...' %}
</span>

<ul>
<li v-for="file in files.{{ field.name }}"> {( file.filename )}</li>
Expand Down
4 changes: 4 additions & 0 deletions djvue/templates/vue/starter.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"

let file_size_msg = "{% trans 'File size should be less than' %}"
let file_size_unit = "{% trans 'Mega Byte' %}"
let duplicate_file_msg = "{% trans 'This file is already uploaded' %}"

</script>
<script src="{% static 'vue/js/script.js' %}"></script>
4 changes: 2 additions & 2 deletions example/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ class ProfileSerializer(serializers.ModelSerializer):
style={"input_type": "password", "rules": "password:@password2"},
)
password2 = serializers.CharField(write_only=True, style={"input_type": "password"})
multiple_file = ListFileField(required=True)
multiple_file = ListFileField(required=True, style={"max_file_size": 100})
multiple_pdf = ListFileField(style={"upload_url": reverse_lazy("example:pdf_upload")})
file = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload")})
file = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload"), "max_file_size": 15})
# cv = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload")})
# file = FileField(required=True)
working_place = WorkSerializer(write_only=True)
Expand Down