I have an upload form that uses AJAX to pass the data to a PHP process file to process the uploading etc. I am trying to add a progress bar to my form while the file is being uploaded.
I have tried a few snippets of code that i have found by searching around but they just don't seem to work. Have tried multiple variations of the following:
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
$('.progress').css({
width: percentComplete * 100 + '%'
});
if (percentComplete === 1) {
$('.progress').addClass('hide');
}
}
}
}, false);
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
$('.progress').css({
width: percentComplete * 100 + '%'
});
}
}, false);
return xhr;
},
url: "upload.php",
type: 'POST',
data: formData,
success: function (data) {
//success
}
});
None of them seem to work though, i have tried alerting out the percentComplete variable and it is always 100, any help would be appreciated, thanks.
I hope this helps -
HTML -
<form id="data" method="post" enctype="multipart/form-data">
<input name="up_vid" type="file" id="up_vid"/>
<br><br>
<button id="uploadBtn">Begin Upload</button>
</form>
<br><br>
<div id="status">PROGRESS HERE</div>
JS
$(document).ready(function() {
$("#uploadBtn").click(function() {
var formData = new FormData($('#data')[0]);
console.log(formData);
$.ajax({
url: "/echo/html/",
type: 'POST',
data: formData,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
$('#status').html('<b> Uploading -> ' + (Math.round(percentComplete * 100)) + '% </b>');
}
}, false);
return xhr;
},
success: function(data) {
$("#status").html('UPLOADED!!');
},
cache: false,
contentType: false,
processData: false
});
return false;
});
});
Live demo - https://jsfiddle.net/im4aLL/n7hwfoxd/4/
You can try tinker with this working template.
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<style type="text/css">
#progressContainer {
display: inline-block;
overflow: hidden;
width: 400px;
height: 10px;
border: 1px solid #333333;
border-radius: 999px;
}
#progress {
display: block;
height: 100%;
background-color: green;
border-radius: 999px;
-o-transition: .1s;
-ms-transition: .1s;
-moz-transition: .1s;
-webkit-transition: .1s;
transition: .1s;
}
</style>
<div>
<form enctype="multipart/form-data" id="form1">
<input name="file" id="file" type="file" />
<input type="button" value="Upload" />
</form>
</div>
<div id="progress-text1">0%</div>
<span id="progressContainer">
<span id="progress" style="width:0%;"></span>
</span>
<div id="progress-text2">0%</div>
<div><progress value="0" id="progress1"></progress></div>
<script>
$('#file').on('change', function() {
$('#progress1').val('0');
});
$(':button').on('click', function() {
if( $('#file').val() == "" ) {
alert('Please choose a file before pressing upload..');
return;
}
var FD = new FormData($('#form1')[0]);
$(FD).serializeArray();
$.ajax({
url: 'fileupload-handler.php',
type: 'POST',
data: FD,
cache: false,
contentType: false,
processData: false,
success: function(data){
alert(data); // Do something with data received
$('#file').val("");
},
// this handles the progress bar
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
var percent_loaded = Math.ceil((e.loaded / e.total)*100);
$('#progress-text1').text(percent_loaded+'% has been uploaded..');
$('#progress-text2').text(percent_loaded+'% has been uploaded..');
$('#progress').css('width', percent_loaded + '%');
if (e.lengthComputable) {
$('progress').attr({
value: e.loaded,
max: e.total,
});
}
} , false);
}
return myXhr;
}
});
});
</script>
The solution is very simple. I hope that the ajax request is triggered only when some action is performed, like on a buttons click or some event.
Now, for that particular event, you do need to start the progress bar. Multiple libraries are there. And, end it when the response is received.
So, the code would:
$(document).on("click","#button", function(){
console.log("Start"); //Start progress bar here
$.ajax({
"type": "POST",
"url": "upload.php",
"success": function()
{
console.log("end"); //End progress bar here
}
});
});
Hope, the logic is easy enough to understand.
Related
The code below is working fine to upload files to SPO through RestAPI. No feedback is received on file upload progress. An alert is thrown once the upload is complete.
I would like to have a progress bar to display the upload percentage and reload this upload page while clicking OK to the successful alert message.
Kindly assist.
<script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script type="text/javascript">
$(document).ready(function () {
init();
});
function init(){
$("#btnUploadFiles").click(function(){
var files=$("#inputTypeFiles")[0].files;
uploadFiles(files[0]); // uploading singe file
});
}
function uploadFiles (uploadFileObj) {
var fileName = uploadFileObj.name;
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var documentLibrary="TEST";
var folderName = "";
var targetUrl = _spPageContextInfo.webServerRelativeUrl + "/" + documentLibrary + "/" + folderName;
var url = webUrl + "/_api/Web/GetFolderByServerRelativeUrl(#target)/Files/add(overwrite=true, url='" + fileName + "')?$expand=ListItemAllFields&#target='" + targetUrl + "'";
uploadFileToFolder(uploadFileObj, url, function (data) {
var file = data.d;
var updateObject = {
__metadata: {
type: file.ListItemAllFields.__metadata.type
},
departname: $("#departname").val(), //meta data column1
Filename: $("#filename").val(), //meta data column2
ACFTREG: $("#ACFTREG").val(), //meta data column3
Date: $("#datepicker").val() //meta data column4
};
url = webUrl + "/_api/Web/lists/getbytitle('"+documentLibrary+"')/items(" + file.ListItemAllFields.Id + ")";
updateFileMetadata(url, updateObject, file, function (data) {
alert("File uploaded & metadata updation done successfully");
}, function (data) {
alert("File upload done but metadata updating FAILED");
});
}, function (data) {
alert("File uploading and metadata updating FAILED");
});
}
function getFileBuffer(uploadFile) {
var deferred = jQuery.Deferred();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(uploadFile);
return deferred.promise();
}
function uploadFileToFolder(fileObj, url, success, failure) {
var apiUrl = url;
var getFile = getFileBuffer(fileObj);
getFile.done(function (arrayBuffer) {
$.ajax({
url: apiUrl,
type: "POST",
data: arrayBuffer,
processData: false,
async: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
},
success: function (data) {
success(data);
},
error: function (data) {
failure(data);
}
});
});
}
function updateFileMetadata(apiUrl, updateObject, file, success, failure) {
$.ajax({
url: apiUrl,
type: "POST",
async: false,
data: JSON.stringify(updateObject),
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"Content-Type": "application/json;odata=verbose",
"X-Http-Method": "MERGE",
"IF-MATCH": file.ListItemAllFields.__metadata.etag,
},
success: function (data) {
success(data);
},
error: function (data) {
failure(data);
}
});
}
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getItems);
function getItems() {
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('L%20-%20MDB%20-%20ACFTREG')/items?$Select=Title&$top=2000",
type: "GET",
headers: {
"accept": "application / json;odata = verbose",
},
success: function(data) {
var results = data.d.results;
var options = "";
for(var i = 0; i < results.length; i++){
options = options + "<option value='" + results[i].Title + "'>" + results[i].Title + "</option>";
}
$("#ACFTREG").append(options);
},
error: function(error) {
alert(JSON.stringify(error));
}
});
}
$( function() {$( "#datepicker" ).datepicker(
{
changeMonth: true,
changeYear: true
}
);} );
</script>
Select File:<input type="File" id="inputTypeFiles" /><br />
Departname: <input id="departname" type="textbox"/><br />
Date: <input type="text" id="datepicker" autocomplete="off" name="hidden"><br />
Filename: <input id="filename" type="textbox"/><br />
ACFTREG: <select id="ACFTREG" class="select">
<option selected="selected">Select</option><br />
<input type="button" id="btnUploadFiles" value="Upload"/><br />
Inside the $.ajax({}) function, you can add the xhr setting inside the ajax.
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total) * 100;
// Place upload progress bar visibility code here
}
}, false);
return xhr;
},
type: 'POST',
//add the rest of ajax settings
check this link for ajax documentation
jQuery/ajax
check this link for example on upload progress
jQuery-upload-progress/example
Explain what is wrong here. First, the run function and its ajax request must be executed. But for some reason the function is executed, and the ajax request is not. It runs right at the very end of the script - after all the functions ... Why is this happening and how to fix it?..
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="id_product_create_form" method="post" enctype="multipart/form-data"></form>
<div class="media_preview_wrap">
<div class="addPhoto">
<div class="addPhotoHeader">
<button type="button" class="button product_images_button">Add</button>
<button id="id_submit" type="button">Submit</button>
</div>
</div>
</div>
<input type="file" name="image" style="display: none" required="" class="product_images" id="">
<script>
var files = [];
$('.product_images_button').click(function() {
$('.product_images').click();
});
$('.product_images').change(function() {
handleFiles(this);
});
$('.media_preview_wrap').on('click', '.thumb', function() {
removeFile($(this).data('id'));
});
$('#id_submit').click(function() {
event.preventDefault();
var $form = $('form'),
formdata = new FormData($form[0]),
$button = $('#id_submit');
formdata.append('content', CKEDITOR.instances.id_content.getData());
function run() {
var product_id = null;
$.ajax($form.attr('action'),{
type: 'POST',
data: formdata,
processData: false,
contentType: false,
success: function(data) {
product_id = data.product_id;
}, error: function(error) {
console.log(error)
}
});
return product_id}
product_id = run();
files.forEach(function(file, index) {
var data = new FormData();
data.append('name', file.name);
data.append('gallery_image', file.file);
uploadFile(event.target.action, data)
.done(function(response) {
removeFile(file.id);
})
.fail(function(error) {
console.log(error);
});
});
});
function handleFiles(input) {
var URL = window.URL || window.webkitURL;
var uniqueId = (new Date()).getTime()
for (var i = 0; i < input.files.length; i++) {
var file = input.files[i];
if (file && file.type.startsWith('image/')) {
uniqueId++;
files.push({
id: uniqueId,
file: file,
name: file.name // задел для возможности переименования файла.
});
var img = $('<img src="'+ URL.createObjectURL(file) +'" class="thumb" data-id="'+ uniqueId +'">');
$('.media_preview_wrap').append(img);
img.on('load', function() {
URL.revokeObjectURL(this.src);
});
}
}
$(input).val('');
}
function removeFile(id) {
files = files.filter(function(file) {
return id !== file.id;
})
$('img[data-id="'+ id +'"]').remove();
}
function uploadFile(url, data) {
return $.ajax({
headers: {'X-CSRFToken': '{{ csrf_token }}' },
type: 'POST',
url: url,
data: data,
processData: false,
contentType: false,
cache: false
});
}
</script>
<style>
.thumb {
width: 150px;
height: auto;
opacity: 0.9;
cursor: pointer;
}
.thumb:hover {
opacity: 1;
}
.product_images {
display: none;
}
</style>
The initial problem is likely due to some browsers having a global event object while others don't.
You are likely getting an error that event is undefined and that would prevent the remaining code to run
Use the argument of the event handler function which always passes in an event object:
$('#id_submit').click(function(event) {
// ^^^
event.preventDefault();
Once that issue is solved... you need to realize that $.ajax is asynchronous and you can't use the new value of product_id until first request completes in the success callback
See How do I return the response from an asynchronous call?
I'm using this jsFuddle http://jsfiddle.net/GvdSy/ for implementing progress bar. But the problem is that bar starts loading only after I get response from API not when I create a request for API.
How can I start loading the progress bar as soon as I Start initiating the API call(click on button) and make it to 100% only after I get a response from API i.e. Progress bar should be consistent with the whole duration.
This is the code I used:
$.ajax({
cache: false,
type: "Post",
data: "",
async: true,
url: "/Apps/AddConnector?connectorId=" + connectorId + "&consumer=" + consumer,
xhr: function () {
var xhr = $.ajaxSettings.xhr();
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
progressBar.css({
width: percentComplete * 100 + '%'
});
}
}, false);
return xhr;
},
success: function (Response) {
if (Response.Status == "Success") {
try { mixpanel.track('Application', { 'App Id': connectorId }, { 'Action': 'added' }); } catch (ex) { }
try { ga('send', 'event', 'Applications', connectorId, 'apps_added'); } catch (ex) { }
progressLabel.text("Installed");
}
else {
progressLabel.text(Response.Message);
setTimeout(function(){flipInstance.slideToggle("slow");},2000);
}
},
error: function (xhr, e) {
if (!HandleAjaxError(xhr, e, "")) {
progressLabel.text(e);
}
},
});
$.ajax({
cache: false,
type: "Post",
data: "",
async: true,
url: "/Apps/AddConnector?connectorId=" + connectorId + "&consumer=" + consumer,
xhr: function () {
var xhr = $.ajaxSettings.xhr();
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable && evt.loaded) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
progressBar.css({
width: percentComplete * 100 + '%'
});
// HERE IS WHERE YOU IMPLEMENT AN ELSE, BEFORE evt.lengthComputable is truthy
} else {
progressBar.css({
width: '2%'
});
}
}, false);
return xhr;
},
success: function (Response) {
if (Response.Status == "Success") {
try { mixpanel.track('Application', { 'App Id': connectorId }, { 'Action': 'added' }); } catch (ex) { }
try { ga('send', 'event', 'Applications', connectorId, 'apps_added'); } catch (ex) { }
progressLabel.text("Installed");
}
else {
progressLabel.text(Response.Message);
setTimeout(function(){flipInstance.slideToggle("slow");},2000);
}
},
error: function (xhr, e) {
if (!HandleAjaxError(xhr, e, "")) {
progressLabel.text(e);
}
},
});
This question is not about tracking the progress of file while it is being uploaded to the server.
In my project, I have ~6GB .csv files that I need to read and filter out some rows based on a certain criteria.
With the known events, it is easy to know when the file got loaded into the browser, but since I am handling pretty large CSVs, I would like to show to the user how much % of the file was loaded to the browser.
To load the CSV, I use the following custom directive:
angular.module('csv-filter')
.directive('fileReader', function() {
return {
scope: {
fileReader:"="
},
link: function(scope, element) {
$(element).on('change', function(changeEvent) {
var files = changeEvent.target.files;
console.log('files', files);
console.log('waiting for onload event..');
if (files.length) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
var filesize = 0;
scope.$apply(function () {
scope.fileReader = {filename: files[0].name, contents: contents};
});
};
r.readAsText(files[0]);
}
});
}
};
});
Here is the link to my app where I am doing all this: https://ahref-csv-filter.herokuapp.com/
There's a progress event. Have you tried it?
With HTML5 you CAN make file uploads with Ajax and jQuery.
The HTML
<form enctype="multipart/form-data">
<input name="file" type="file" />
<input type="button" value="Upload" />
</form>
<progress></progress>
Now the Ajax submit with the button's click:
$(':button').click(function(){
var formData = new FormData($('form')[0]);
$.ajax({
url: 'upload',
type: 'POST',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',progressFunction, false);
}
return myXhr;
},
beforeSend: beforeSendHandler,
success: completeHandler,
error: errorHandler,
data: formData,
cache: false,
contentType: false,
processData: false
});
});
Now if you want to handle the progress.
function progressFunction(e){
if(e.lengthComputable){
$('progress').attr({value:e.loaded,max:e.total});
}
}
You can use ng-file-upload. It is a very neat directive that enable you to do multi-file upload and track the progress of your uploading event.
ng-file-upload
Official Samples
Sample
//inject angular file upload directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
$scope.uploadFiles = function(files, errFiles) {
$scope.files = files;
$scope.errFiles = errFiles;
angular.forEach(files, function(file) {
file.upload = Upload.upload({
url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
data: {file: file}
});
file.upload.then(function (response) {
$timeout(function () {
file.result = response.data;
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
file.progress = Math.min(100, parseInt(100.0 *
evt.loaded / evt.total));
});
});
}
}]);
**strong text**
.thumb {
width: 24px;
height: 24px;
float: none;
position: relative;
top: 7px;
}
form .progress {
line-height: 15px;
}
}
.progress {
display: inline-block;
width: 100px;
border: 3px groove #CCC;
}
.progress div {
font-size: smaller;
background: orange;
width: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script src="https://angular-file-upload.appspot.com/js/ng-file-upload-shim.js"></script>
<script src="https://angular-file-upload.appspot.com/js/ng-file-upload.js"></script>
<body ng-app="fileUpload" ng-controller="MyCtrl">
<h4>Upload on file select</h4>
<button ngf-select="uploadFiles($files, $invalidFiles)" multiple
accept="image/*" ngf-max-height="1000" ngf-max-size="1MB">
Select Files</button>
<br><br>
Files:
<ul>
<li ng-repeat="f in files" style="font:smaller">{{f.name}} {{f.$errorParam}}
<span class="progress" ng-show="f.progress >= 0">
<div style="width:{{f.progress}}%"
ng-bind="f.progress + '%'"></div>
</span>
</li>
<li ng-repeat="f in errFiles" style="font:smaller">{{f.name}} {{f.$error}} {{f.$errorParam}}
</li>
</ul>
{{errorMsg}}
</body>
Use ng-file-upload directive.
check link http://ngmodules.org/modules/ng-file-upload
I am trying to make a progress bar to show the user how much of the file is uploaded, I am using ajaxSubmit and uploadprogress function, however this function doesn't update it just gives me 100 and that is it:
Here is my JS code:
function UploadImage(){
$('#new-post-upload-images').ajaxSubmit({
dataType: "json",
beforeSend: function(a,f,o) {
$('input.images').unwrap().css('display','none');
$('#new_post_overlay,#upload_plus,#upload_wrapper .edit-menu-post').remove();
$(".new_post_btn").attr('disabled', true);
$(".load_new_post").show();
},
uploadProgress: function(event, position, total, percentComplete) {
console.log(percentComplete + '%');
},
complete: function(XMLHttpRequest, textStatus) {
var data= XMLHttpRequest.responseText;
var jsonResponse = JSON.parse(data);
$(".load_new_post").hide();
$('#new_post_wrapper').append('<div class="edit-menu-post"><a class="delete dismiss_image dismiss icon-cancel" title="Remove"><span>Delete</span></a><a class="repos-drag icon-drag" title="Reposition"><span>Reposition</span></a></div><div style="width:100%;height:100%;background-repeat: no-repeat;background-size: cover;position: relative;" id="preview"></div>').parent().find('.bg-port').val('0px 0px');
$('#preview').css('background-position', '0 0').css('background-image', 'url(' + jsonResponse[0]["path"] + ')');
var ids = $.map(jsonResponse, function(n){
return n["id"];
});
$('#uploaded_images_ids').val(ids.join("#"));
$(".new_post_btn").attr('disabled', false);
}
});
}
Here is my Ruby and HTML code:
<div id="upload_wrapper">
<%= form_tag(upload_images_path, :multipart => true, method: :post ,id: "new-post-upload-images") do %>
<div class="new_photo_viewport">
<div class="load_new_post" style="340px">
<div><h2>Uploading <%= image_tag("ajax-loader2.gif") %></h2></div>
</div>
<div class="new_post_error edit-menu-post" style="background-color: #fff;">
<span><b>Recommendation:</b> Picture dimensions should be at least 800 x 600 for better quality and the size doesn't exceed 12MB</span>
</div>
<div id="new_post_wrapper" class="new_post_viewport" style="display:block;width:100%;height:100%;">
<div class="add_image_button" id="new_post_overlay">
<span class="icon-camera" id="upload_plus"><br><span>Upload</span></span>
<%= file_field_tag "images[]", type: :file, accept: "image/*" ,class: "images" %>
</div>
</div>
</div>
<% end %>
</div>
Inside beforeSend: function(a,f,o) { add:
a.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
console.log(evt.loaded / evt.total);
}
}, false);
Source: JQuery ajax progress - HTML5
I found the solution for this problem, i had to deploy my code to the server, i was trying it on my localhost that is way it always gave me 100%
try this
$.ajax({
xhr : function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e){
if(e.lengthComputable){
//you can get percent here
var percent_total = Math.round((e.loaded / e.total) * 100);
//then do with your progress bar, i used bootstrap here
$('#theProgressBar').attr('aria-valuenow', percent_total).css('width', percent_total + '%').text(percent_total + '%');
}
});
return xhr;
},
url: url,
data: formdata,
processData: false,
contentType: false,
type: 'POST',
dataType: "json",
success: function (response) {
},
err: function(err){
}
});