I have a form that takes a json file and POSTs to a server side process. It's a lengthy process and I want to message it's progress back to the user in real time with multiple messages.
What are my options?
This process can take 10-15 minutes or higher. I am not looking for the answer "AJAX". there is more to it than that.
this is what I got for a form:
<form method="POST" accept-charset="UTF-8" class="smart-form" id="import-course" enctype="multipart/form-data">
<fieldset>
<div class="row">
<section class="col col-md-12">
<label class="input input-file">
<input class="button" name="import" type="file">
</label>
</section>
</div>
</fieldset>
<footer>
<button class="btn btn-primary" id="submit-import-file" type="button">Save</button>
<a onclick="history.back();" class="btn btn-default">Cancel</a>
</footer>
</form>
Here is my ajax:
$(document).ready(function(){
$("#submit-import-file").on('click',function(){
console.log('click');
$('#import-course').hide();
var formData = new FormData($('#import-course')[0]);
$.ajax({
url: '{{URL::route("courses.import")}}', //Server script to process data
type: 'POST',
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // Check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
//Ajax events
success: function(data){
console.log(data);
},
// Form data
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false
});
});
});
function progressHandlingFunction(e){
console.log(e);
}
and here is my server side pay attention to the comments.
$errors = 0;
$file = Input::file('import');
$fileName = $file->getClientOriginalName();
$destinationPath = app_path()."/storage/files/";
$file->move($destinationPath, $fileName);
$course = json_decode(File::get($destinationPath.$fileName));
if(!File::isDirectory($destinationPath.$course->code)){
File::makeDirectory($destinationPath.$course->code,0777,true,true);
//message back directory created
}
foreach($course->file as $file){
if(FileManger->processfile($file)){
//message back $file->name imported
}else{
//message back error importing $file->name
}
}
return "import complete";
So now.. How do i get the comment areas to be messaged back to the user while this processes. not after.
You should use Ajax to post the data to the php page without refreshing. The below code will display "Loading" until the ajax call is complete. You could use a gif or something instead. It's more difficult to do a progress bar / percentage complete but you could look at this answer as a reference. PHP Ajax Upload Progress Bar
$.ajax({
url: "domain.com/url",
type: "POST",
data: data,
cache: false,
beforeSend: function() {
$('#response').html("Loading");
},
success: function(data) {
$('#response').html(data);
}
}
You can still use a jquery progressbar. Write the progress of the processing out to the UI and calculate some form of percentage based on the progress through the processing. That of course assumes there is more than one step to the processing of course...! A progress bar that goes from 0 to 100% in one step isn't terribly useful.
Related
I am attempting to create an upload document which will upload a profile picture. I am having trouble capturing the data from the changePicture form which only has an input for the images and a submit. I have never used the FormData object to date, so I am still learning around this. Any guidance would be useful.
See my HTML
<form id="changePicture" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Update Your Profile Picture</label>
<input type="file" id="profilePic" class="form-control" name="profilePic">
<input type="hidden" value="<?php echo $id; ?>" name="id">
</div>
<button type="submit" id="updateProfileBtn" class="btn btn-success float-right">Upload Image</button>
</form>
Here is my AJAX code:
function updateProfilePic(){
$("#changePicture").on("submit", function(e) {
e.preventDefault();
$("#spinner").show();
setTimeout(function(){
$.ajax({
url: "../ajax/admin/updateProfilePic.php",
type: "POST",
data: new FormData(this),
cache: false,
contentType: false,
processData: false,
success: function(result){
$("#spinner").hide();
$("#changePicture").append(result);
setTimeout(function(){
$("#changePicture").slideDown();
}, 1500);
}
});
}, 3000);
});
}
The PHP file at this moment only echos out "Working" to see it accesses the page alright, which it does. However, when I attempt to locate the file through a variable nothing has been sent and returns undefined index.
this will be undefined because it's inside ajax's scope
Try:
me = this;
$.ajax({
url: "../ajax/admin/updateProfilePic.php",
type: "POST",
data: new FormData(me),
...
As, for me, when using ajax I always prefer to base64encode the image and pass it as a JSON to PHP but i guess that's a personal preference...
Why are you wrapping your AJAX call in a
setTimeout(function() {..})
?
By doing this, you cannot simply write new FormData(this), because the this context does not refer to the form that you are looking for.
Try executing the code without the timeout, or try storing the form data in a global variable
Edit: Example added:
var myFormData;
function updateProfilePic(){
$("#changePicture").on("submit", function(e) {
e.preventDefault();
$("#spinner").show();
myFormData = new FormData(this);
setTimeout(function(){
$.ajax({
url: "../ajax/admin/updateProfilePic.php",
type: "POST",
data: myFormData,
....
I have a form with some fields (first name, last name and profile picture) that looks like this:
<form>
<div class="row">
<div class="col-lg-6">
<label class="control-label">First Name:</label>
<input class="form-control" type="text" placeholder="Enter first name.." id="firstName">
</div>
<div class="form-group col-lg-6">
<label class="control-label">Last Name:</label>
<input class="form-control" type="text" placeholder="Enter last name.." id="lastName">
</div>
</div> <!-- /row -->
<div class="row">
<div class="form-group col-lg-6">
<label class="control-label">profile picture:</label>
<div class="dropzone dropzone-previews" id="profilbildDropzone">
<div class="fallback">
<input name="file" type="file" multiple="multiple">
</div>
</div>
</div>
</div> <!-- /row -->
<hr />
<div class="form-action">
<button type="button" class="btn btn-primary waves-effect waves-light" id="sweet-ajax">Submit Data</button>
</div>
</form>
When the user clicks on submit data I call a Sweet-Alert dialog that asks if the user is sure about the action he tries. If he clicks yes I want to submit the data via AJAX to an PHP script that does all the rest (storing the image on the server, save the data in my database and so on):
<script type="text/javascript">
SweetAlert.prototype.init = function () {
//Ajax
$('#sweet-ajax').click(function () {
swal({
title: "Sure?",
text: "Clicking on yes submits the data!",
type: "warning",
showCancelButton: true,
closeOnConfirm: false,
confirmButtonText: "Yes!",
cancelButtonText: "Cancel",
showLoaderOnConfirm: true,
confirmButtonClass: 'btn btn-success',
cancelButtonClass: 'btn btn-danger m-l-10',
preConfirm: function(givenData){
return new Promise(function(resolve, reject) {
setTimeout(function(){
inputNameFirst = document.getElementById("firstName").value;
inputNameLast = document.getElementById("lastName").value;
resolve()
}, 2000)
})
},
allowOutsideClick: false
}).then(function(givenData){
$.ajax({
type: "post",
url: "../assets/php/addUser.php",
data: {done: "success", fN: inputNameFirst, ln: inputNameLast},
dataType: 'JSON',
success: function(data) {
if(data.status === 'success'){
swal({
type: 'success',
title: 'Good job!',
html: 'all saved now!'
})
}else if(data.status === 'error'){
swal({
type: 'error',
title: 'Oh No!!',
html: 'Nope sorry, there was an error: <br /><pre>'+ JSON.stringify(data) + '</pre>'
})
}
}
})
}, function(dismiss) {
// dismiss can be 'overlay', 'cancel', 'close', 'esc', 'timer'
if (dismiss === 'cancel') {
swal(
'Got you!',
'Nothing changed. Good luck.',
'error'
)
}
})
});
},
//init
$.SweetAlert = new SweetAlert, $.SweetAlert.Constructor = SweetAlert
}(window.jQuery),
//initializing
function ($) {
"use strict";
$.SweetAlert.init()
}(window.jQuery);
</script>
I also set up the DropZone on my site so that I can also have optional fields in my form (from here):
jQuery(document).ready(function() {
$("div#profilbildDropzone").dropzone({
//store images in this directory
url: "../assets/images/uploads",
dictDefaultMessage: "Drop image here or click.",
autoProcessQueue: false,
maxFiles: 1,
uploadMultiple: true,
parallelUploads: 100,
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button#sweet-ajax").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
});
this.on("errormultiple", function(files, response) {
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
});
});
But I do not get it how I upload the picture or give it so my php script.
In this line:
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
I'm supposed to upload the picture or what? Can I call this function inside my SWAL function or pass the data to my SWAL function where it gets send to the PHP script?
Sadly I haven't found any usable example that gives me a clear hint on how I could solve this specific problem.
You are not written logic send data via ajax to server side (i.e PHP). On click of the submit button you are telling Dropzone.js to processQueue(). But that itself will not post the data to the server via ajax.
On sendingmultiple event you need to get form data and assign it to formObject, then DropzoneJS will take care of posting data along file/image to the PHP.
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button#sweet-ajax").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Append all form inputs to the formData Dropzone will POST
var data = $form.serializeArray();
$.each(data, function (key, el) {
formData.append(el.name, el.value);
});
});
}
Next on the PHP server side get the posted data and files/images likes this.
<?php
//get form data
echo '<pre>';print_r($_POST);echo '</pre>';
//get posted files
echo '<pre>';print_r($_FILES);echo '</pre>';
exit;
Next write your logic upload files/images and also updating the database with posted data.
Also check I have written detailed tutorials on how to upload images with form data on button click using DropzoneJS and PHP via ajax.
Ajax Image Upload Using Dropzone.js with Normal Form Fields On Button Click Using PHP
I have a form that has a simple file input.
<form id="uploadFile" name="uploadFile" action="addFile.php" method="POST" enctype="multipart/form-data">
<input type="hidden" value="" name="uploadWUID" id="uploadWUID">
<p>Please upload a signed and completed write-up in PDF format. Please file the hardcopy of the write-up per company policy.</p>
<div class="input-group" style="margin-bottom:7px;">
<span class="input-group-btn">
<span class="btn btn-primary btn-file">
Browse… <input type="file" id="reportImport" name="reportImport">
</span>
</span>
<input type="text" class="form-control" readonly>
</div>
</form>
There is some local javascript that puts the filename in the text input, but the text input is not used in the PHP file.
The uploadWUID is set dynamically and is passed to add the uploaded file to a specific record in a database.
When I submit the form it works just fine. My browser redirects to addFile.php, success is echoed out, the file is moved to the correct directory and the database is updated.
My issues comes when I add return false to my ajax form submission. I get an error back from the php file stating it couldn't find the index when processing $filename = $_FILES['reportImport']['name']; and my upload/database update fails.
$('#uploadFile').submit(function() {
$.ajax({
data: $(this).serialize(),
type: $(this).attr('method'),
url: $(this).attr('action'),
success: function(response) {}
});
return false;
});
Change script code
$('#uploadFile').submit(function() {
var formData = new FormData($(this)[0]);
$.ajax({
data: formData,
type: $(this).attr('method'),
url: $(this).attr('action'),
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function(response) {
console.log(response);
alert(response);
return false
}
});
return false;
});
I am trying to upload files via AJAX using FormData. If I submit the AJAX call without selecting any files to upload, the post works fine, and other fields (that are not file uploads) are received on the server OK. If I select a file to upload though, the call arrives at the server with no data whatsoever (in PHP, the $_POST and $_FILES arrays are both completely empty). I understand this can happen if you fail to tell jQuery not to set the contentType, but I am setting contentType and processData to false and it still won't send the data.
Here is my code:
function AddComment(taskid) {
var newnote = $('#newnote_'+taskid).val();
if(newnote != '') {
$('#tasklist *').css('cursor', 'progress');
var formData = new FormData();
$('.upload-' + taskid).each(function() {
if (this.files[0]) {
formData.append($(this).attr('name'), this.files[0]);
}
});
formData.append("taskid", taskid);
formData.append("newnote", newnote);
$.ajax({
url: '/modules/task/ajax/ajaxAddComment.php',
data: formData,
processData: false,
contentType: false,
type: 'post',
success: function(data){
alert(data);
}
});
}
}
I'm sure I'm doing something stupid, but I can't see what...?
Edit: Here is the HTML:
<form id="frmNewComment544" enctype="multipart/form-data" method="post" action="">
<div>
<textarea style="width:100%;" cols="30" rows="5" id="newnote_544"></textarea>
</div>
<div>
<input type="button" onclick="AddComment(544)" value="Append Comment">
</div>
<div class="attachment-browsers" id="attachmentBrowsers544" style="display: block;">Attachments will be uploaded when you append a comment.
<div>
<input type="file" id="upload_544_151ab3cfe69" name="upload_544_151ab3cfe69" class="upload-544">
</div>
<div>
<input type="file" id="upload_544_3y4afe6eg7a" name="upload_544_3y4afe6eg7a" class="upload-544">
</div>
</div>
</form>
Edit 2: OK, the problem only occurs when uploading relatively large files (not massive - in this case it was 10MB). Small files upload OK. So now the question is why I cannot upload large files using this method?
I knew it would be something stupid!
My php.ini had the default 2MB limit for file uploads. D'oh.
I don't see any reference to your form.
May be you would do it like this:
.....
var form = $('form#frmNewComment544');
var formdata = false;
if (window.FormData){
formdata = new FormData(form[0]);
}
var formAction = form.attr('action');
$.ajax({
url: formAction,
data : formdata ? formdata : form.serialize(),
....
I want to upload a file asynchronously using jQuery - without using any PLUGIN.
JQuery is very new to me and after looking at various forums I ended up with this code :
HTML:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
$('#myform').submit(function() {
var fileInput = document.getElementById('file');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file);
$.ajax({
type: "POST",
url: "upload.php",
data: formData,
processData: false,
contentType: 'multipart/form-data',
beforeSend: function (x) {
if (x && x.overrideMimeType) {
x.overrideMimeType("multipart/form-data");
}
},
success:function(msg){
//alert( "Data Uploaded: " + msg );
document.getElementById('display').innerHTML = msg;
}
});
return false;
});
});
</script>
</head>
<body>
<form enctype="multipart/form-data" id="myform" name="myform" method="POST">
<input name="file" type="file" id="file" name="file"/>
<input type="text" name="txtValue" value="" id="txtValue">-->
<input type="submit" value="Upload" id="button" name="button"/>
<div id="display"></div>
</form>
</body>
</html>
PHP:
<?php
$uploaddir = './uploads/';
$file = $uploaddir . basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], $file)) {
$value = "success";
}
else {
$value = "error";
}
echo $value;
?>
This code is not working and everytime the "display" DIV is printing "error". Please help me out.
Take a hidden div. Inside that div take a iframe and set the form's target to the iframe's id.
In jQuery. In after document ready function add a load event handler (say LEH)to the iframe.
So that when the form is submitted and file is uploaded and iframe is loaded then the LEH will get called
This will act like success event.
Note: you need to make minor tweaks as for the first time when the page is loaded then also the iframe is loaded. So there will be a first time check also.
With HTML5 you can make file uploads with Ajax and jQuery. Not only that, you can do file validations (name, size, and MIME-type) or handle the progress event with the HTML5 progress tag (or a div).
The HTML:
<form enctype="multipart/form-data">
<input name="file" type="file" />
<input type="button" value="Upload" />
</form>
<progress></progress>
You can do some validation if you want.
$(':file').change(function(){
var file = this.files[0];
var name = file.name;
var size = file.size;
var type = file.type;
//Your validation
});
Now the Ajax submit with the button's click:
$(':button').click(function(){
var formData = new FormData($('form')[0]);
$.ajax({
url: 'upload.php', //Server script to process data
type: 'POST',
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // Check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
//Ajax events
beforeSend: beforeSendHandler,
success: completeHandler,
error: errorHandler,
// Form data
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false
});
});
Now if you want to handle the progress.
function progressHandlingFunction(e){
if(e.lengthComputable){
$('progress').attr({value:e.loaded,max:e.total});
}
}
SOURCE
You can use following plugins to upload files using ajax:
jQuery Form Plugin
Uploadify
The plugin in the first link provides some very useful callbacks. You can check the documentation at the given link.
I have user Jquery Form Plugin in my project.
JQuery the raw xhr object is wrapped in jqXhr Object which doesn't have any reference to the new upload property of the xhr.
Hope you can start with this below example.
html:
<input type="file" class="text-input" size="50" id="file_upload" value="" name="file_upload"/>
var formData = new FormData($('form')[0]);
$.ajax({
url: '/files/add_file', //server script to process data
type: 'POST',
xhr: function() { // custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // check if upload property exists
//myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // for handling the progress of the upload
}
return myXhr;
},
dataType: 'JSON',
beforeSend: beforeSendHandler,
success: function(data) {
if (data.error){
showMessage(data.html, false, false);
}
else{
showMessage(data.html, false, false);
setTimeout("window.location = 'path/to/after/uploading';",450)
}
},
error: function(data) {
showMessage(data.html, false, false);
},
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});