I'm working on a project (in Django) where I have created a page to add data information about a file and then add the file itself.
When 'More datasets' button is clicked, it adds another field to upload another file.
This can be done to attach as many files as the end-user wants in one go.
What I need is to upload all the attached files once 'Upload data-sets' is clicked and individual progress bar should be displayed.
So far, I have run through multiple tutorials but came kinda close using Vitor Freitas's tutorial.
JS code :
$(function(){ /*$("#add_new_dataset").click(function(){ $(".file").click(); });*/ $(".file").fileupload({ dataType: 'json', sequentialUploads: true, /* Send the files one by one */ start: function(e){ /* When the upload process starts, show the modal */ $("#modal-progress").modal("show"); }, stop: function(e){ /* When the upload progress finalizes, hide the modal */ $("#modal-progress").modal("hide"); }, progressall: function(e, data){ /* Update the progress bar */ var progress = parseInt(data.loaded / data.total * 100, 10), strProgress = progress + "%"; $(".progress-bar").css({"width": strProgress}); $(".progress-bar").text(strProgress); }, done: function(e, data){ if(data.result.is_valid){ $("#gallery tbody").prepend( "<tr><td><a href='" + data.result.url + "'>" + data.result.name + "</a></td></tr>" ); } } }) }); Template code :
<form id="form" method="POST" enctype="multipart/form-data"> {% csrf_token %} <div class="container-fluid" id="datasets" style="margin: 0px; padding: 0px;"> <div class="row" onfocusin="populateFilename(this);"> <label class="col-md-2">User Name :</label> <input class="col-md-2" type="text" id="username" name="user_name" value="{{ user.username }}" readonly /> <label class="col-md-2">Data-set :</label> <input class="col-md-2" type="text" placeholder="Enter dataset" name="dataset" required /> <label class="col-md-2">Creation Date :</label> <input class="col-md-2" type="date" placeholder="YYYY-MM-DD" name="creation_date" required /> <label class="col-md-2">Beam Line:</label> <input class="col-md-2" type="text" placeholder="Enter beam line" name="beamline" required /> <label class="col-md-2">Data-set file:</label> <input class="col-md-2 file" type="file" name="file" data-url="{% url 'add_data_sets' %}" data-form-data='{"csrfmiddlewaretoken": "{{ csrf_token }}"}' required /> <label class="filename"></label> <div class="modal fade" id="modal-progress" data-backdrop="static" data-keyboard="false"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">Uploading...</h4> </div> <div class="modal-body"> <div class="progress"> <div class="progress-bar" role="progressbar" style="width: 0%;">0%</div> </div> </div> </div> </div> </div> </div> </div> <div style="align: center; margin-top: 5px;"> <div class="container btn-group btn-group-justified btn-group-lg"> <a onmouseup="addRow();" class="btn btn-outline-secondary" style="width: 50%;">More Datasets</a> <button type="submit" class="btn btn-outline-primary" name="add_new_dataset" id="add_new_dataset">Submit Data-set</button> </div> </div>
What should I do? I'm not very good at AJAX but I can't see any code that works to send the data to the server side. Is it so or am I missing something? Kindly ignore my ignorance on the topic and thanks to all in advance.
EDIT :
The JS code has been rewritten based on some of the answers.
document.getElementById('add_new_dataset').onclick = function() { $(this).preventDefault(); console.log('Files uploading begin'); form_data = new FormData(); const files = document.getElementsByName('file'); let count = 0; for(let i = 0; i < files.length; i++){ count++; form_data.append("file", files[i]); } $.ajax({ url: "/add_data_sets", dataType: 'json', contentType: false, processData: false, data: form_data, type: 'POST', success: function(files, response, xhr, pd){ $('.file').show(); if(files.status != false){ $('.progress-bar').val('/location/' + files.filename); var fileData = files.filename; console.log('Files uploading...'); } else{ alert(files.filename); } }, /*xhrFields: { onprogress: function(e) { if(e.lengthComputable) { let percentCompleted = e.loaded / evt.total; pBar.style.width = percentComplete; pBar.innerHTML = percentComplete + "%"; console.log('Percent complete : ' + percentComplete); } } }*/ xhr: function(){ let xhr = $.ajaxSettings.xhr(); xhr.upload.onprogress = function(e) { let percentCompleted = e.loaded / evt.total * 100; pBar.style.width = percentComplete; pBar.innerHTML = percentComplete + "%"; console.log('Percent complete : ' + percentComplete); }; return xhr; } }); //}); }; This is just the upload code block. The sending of the data from client-side to server-side works perfectly but it makes be suspicious as the 'console.log' calls aren't being triggered when the code runs through it. Is it so that the data is, somehow, being submitted normally and this code is doing nothing.
EDIT2 : A new JS function:
function upload() { console.log('Upload function begins'); let pBar = document.getElementsByClassName('progress-bar')[0], progressWindow = document.getElementById('modal-progress'), formData = new FormData(document.forms.form), xhr = new XMLHttpRequest(), percent = 0; console.log('Form Data created'); // Start upload xhr.upload.onloadstart = function() { //$('#modal-progress').hide().fadeIn(); //progressWindow }; // Track upload progress xhr.upload.onprogress = function(event) { percent = parseInt(event.loaded / event.total * 100); pBar.innerHTML = percent + "%"; pBar.style.width = percent + "%"; //console.log(percent + '% completed'); //console.log('Uploaded event.loaded of event.total'); }; // Report if ends with an error xhr.upload.onerror = function() { console.log('An error has occurred') }; // Track completion: Both successful or not xhr.upload.onloadend = function() { //$('#modal-progress').fadeOut().hide(); console.log('Upload complete with or without error ' + xhr.status); }; // Track progress: Triggered on successful completion xhr.upload.onload = function() { console.log('Uploading complete'); progressWindow.hidden = True; }; xhr.open("POST", "{% url 'add_data_sets' %}", true); // The 'setRequestHeader' function can only be called when xhr is opened. //xhr.setRequestHeader('csrfmiddlewaretoken', '{{ csrf_token }}'); //xhr.setRequestHeader('test-info', 'something'); xhr.setRequestHeader('Content-Type', 'application/gzip'); xhr.send(formData); }
The function works fine now. It sends the data completely fine but on the development server console screen I get this error.
Forbidden (CSRF token missing or incorrect.): /accounts/add_data_set/ [22/Feb/2020 15:36:06] "POST /accounts/add_data_set/ HTTP/1.1" 403 2513 I even checked logged the POST data being send to the server and it does contain the csrf token
<QueryDict: {'csrfmiddlewaretoken': ['WREoIV0aY4B2XyrU7d9Qw8kMwiokXqwWsmbc2QSHX5VQ0EaYjjeuv7PeysMJjecp'], 'user_name': ['rakesh'], 'dataset': ['r'], 'creation_date': ['2020-02-22'], 'beamline': ['r']}> I'm kind of confused. Is this an issue?


$("#form").on("submit", function() {...})(instead of the click event on the button) or removetype="submit"on your button.type="submit". It worked fine but the page stopped refreshing. I have used the technique I've included in my second edit and I'm facing an issue.