Ajax calls half working ... file uploaded but javascript not executed - javascript

I'm sorry for that question but I have a persistent bug and I don't understand at all what's happening ...
I have an ajax upload function that is working fine
function startUp(hash) {
$('#file_up_form').ajaxForm({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRF-Token", '{{ Session::token() }}' );
xhr.setRequestHeader('Sha-Sha',hash);
//other stuff
},
uploadProgress: function(event, position, total, percentComplete) {
//some stuff
},
complete : function(xhr) {
//some stuff
},
error : function(xhr) {
//some stuff
}
});
}
When I call it that way :
$("#start_up_button").on('click', function() {
if(checkFile()){
startUp('f4274dd2284704f1158b2cecd71666a37ba5b949f97fc521974f98fa3dd0ea706cca7253244e20f2a4c4c694052097c45260edfe679c9e7b56896858a34839cd');
//getHash();
}
else{
$('#myModalerror').modal('show');
$("#myModalerror").css("z-index", "1500");
}
});
Everything works fine.
But when I uncomment the second line and comment the first to call it from :
function getHash(){
input = document.getElementById('fileToUpload');
file = input.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var shaObj = new jsSHA(reader.result,"BYTES");
var hash = shaObj.getHash("SHA-512", "HEX");
console.log(hash);
startUp(hash);
};
reader.readAsBinaryString(file);
}
Nothing work for ajax : the console.log display the correct hash but there are no headers set, and nothing from '//some stuff' works ... But the file is uploaded !! (??) I tried to wrap the call with a
setTimeout(function() {
startUp(hash);
}, 200);
but Firefox just crash. Any idea ??
thx

The behaviour of ajaxForm() in $('#file_up_form').ajaxForm({ ... }) is not to trigger an AJAX request.
It is an event binding function. (I've not gone through the API documentation, but probably it binds a form submit event to one of its inner library function)
To actually trigger an AJAX request you've to add a <input type="submit" > button inside the HTML <form>, and just click it. (Library will prevent traditional form submission, and submit it via AJAX)
Example implementation:
JS:
<script type="text/javascript">
$(document).ready(function(){
$("#file_up_form").ajaxForm({ // bind library function to the form
beforeSend: function(xhr){
input = document.getElementById('fileToUpload');;
file = input.files[0];
if(file){
var reader = new FileReader();
reader.readAsBinaryString(file);
var shaObj = new jsSHA(reader.result,"BYTES");
var hash = shaObj.getHash("SHA-512", "HEX");
xhr.setRequestHeader('Sha-Sha', hash);
}else{
alert("First, please select a file to upload.");
return false;
}
},
uploadProgress: function(event, position, total, percentComplete){ },
success: function() { },
complete: function(response) { },
error: function() { }
});
});
</script>
HTML:
<body>
<form id="file_up_form" action="upload.php" method="post">
<input type="file" id="fileToUpload" name="uploadedfile" />
<!-- Click on submit to perform AJAX call -->
<input type="submit" value="Upload">
</form>
</body>

Thx,
But that can't work because javascript is ***** not synchrone and I need to force the synchronisation with the reader.onload() callback and then call ajax ... the ajax request will be sent, no matter if the hash is computed or not, if I am inside .ajaxForm() it's over, even the setTimeout(function(){...}) is asynch itself too, so it has no effect the ajax request is sent ... or if I place it in an other place it just crash firefox ...
I have an upload button to trigger the request as you mention of course, and it is the only trigger I have to process the computation of the sha-512 first and then trigger ajax with the form binding.
But what I don't understand is :
why "startUp('ARandomHash');" works perfectly inside the $("#start_up_button").on('click', function() {...}); and "hash=...; console.log(hash); startUp(hash);" print the correct hash but ajax is a total fail inside the reader.onload() callback ... the event is trigger by the same click event, it has just 2 scope of execution more ...
I don't think I am loosing the submit event with these 2 scope more because the file is uploaded correctly ... it is just the beforeSend:..., uploadProgress:..., etc that are not executed.
I think I'll rather try to cast hash, it may be a character encoding problem, it has no sense otherwise, it should fail for the "startUp('ARandomHash');" as well ...
But thx, if someone has a better idea =)

Related

Cancelling AJAX request if previous AJAX response hasn't been received [duplicate]

Is it possible that using jQuery, I cancel/abort an Ajax request that I have not yet received the response from?
Most of the jQuery Ajax methods return an XMLHttpRequest (or the equivalent) object, so you can just use abort().
See the documentation:
abort Method (MSDN). Cancels the current HTTP request.
abort() (MDN). If the request has been sent already, this method will abort the request.
var xhr = $.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
//kill the request
xhr.abort()
UPDATE:
As of jQuery 1.5 the returned object is a wrapper for the native XMLHttpRequest object called jqXHR. This object appears to expose all of the native properties and methods so the above example still works. See The jqXHR Object (jQuery API documentation).
UPDATE 2:
As of jQuery 3, the ajax method now returns a promise with extra methods (like abort), so the above code still works, though the object being returned is not an xhr any more. See the 3.0 blog here.
UPDATE 3: xhr.abort() still works on jQuery 3.x. Don't assume the update 2 is correct. More info on jQuery Github repository.
You can't recall the request but you can set a timeout value after which the response will be ignored. See this page for jquery AJAX options. I believe that your error callback will be called if the timeout period is exceeded. There is already a default timeout on every AJAX request.
You can also use the abort() method on the request object but, while it will cause the client to stop listening for the event, it may probably will not stop the server from processing it.
Save the calls you make in an array, then call xhr.abort() on each.
HUGE CAVEAT: You can abort a request, but that's only the client side. The server side could still be processing the request. If you are using something like PHP or ASP with session data, the session data is locked until the ajax has finished. So, to allow the user to continue browsing the website, you have to call session_write_close(). This saves the session and unlocks it so that other pages waiting to continue will proceed. Without this, several pages can be waiting for the lock to be removed.
It's an asynchronous request, meaning once it's sent it's out there.
In case your server is starting a very expensive operation due to the AJAX request, the best you can do is open your server to listen for cancel requests, and send a separate AJAX request notifying the server to stop whatever it's doing.
Otherwise, simply ignore the AJAX response.
AJAX requests may not complete in the order they were started. Instead of aborting, you can choose to ignore all AJAX responses except for the most recent one:
Create a counter
Increment the counter when you initiate AJAX request
Use the current value of counter to "stamp" the request
In the success callback compare the stamp with the counter to check if it was the most recent request
Rough outline of code:
var xhrCount = 0;
function sendXHR() {
// sequence number for the current invocation of function
var seqNumber = ++xhrCount;
$.post("/echo/json/", { delay: Math.floor(Math.random() * 5) }, function() {
// this works because of the way closures work
if (seqNumber === xhrCount) {
console.log("Process the response");
} else {
console.log("Ignore the response");
}
});
}
sendXHR();
sendXHR();
sendXHR();
// AJAX requests complete in any order but only the last
// one will trigger "Process the response" message
Demo on jsFiddle
We just had to work around this problem and tested three different approaches.
does cancel the request as suggested by #meouw
execute all request but only processes the result of the last submit
prevents new requests as long as another one is still pending
var Ajax1 = {
call: function() {
if (typeof this.xhr !== 'undefined')
this.xhr.abort();
this.xhr = $.ajax({
url: 'your/long/running/request/path',
type: 'GET',
success: function(data) {
//process response
}
});
}
};
var Ajax2 = {
counter: 0,
call: function() {
var self = this,
seq = ++this.counter;
$.ajax({
url: 'your/long/running/request/path',
type: 'GET',
success: function(data) {
if (seq === self.counter) {
//process response
}
}
});
}
};
var Ajax3 = {
active: false,
call: function() {
if (this.active === false) {
this.active = true;
var self = this;
$.ajax({
url: 'your/long/running/request/path',
type: 'GET',
success: function(data) {
//process response
},
complete: function() {
self.active = false;
}
});
}
}
};
$(function() {
$('#button').click(function(e) {
Ajax3.call();
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="button" type="button" value="click" />
In our case we decided to use approach #3 as it produces less load for the server. But I am not 100% sure if jQuery guarantees the call of the .complete()-method, this could produce a deadlock situation. In our tests we could not reproduce such a situation.
It is always best practice to do something like this.
var $request;
if ($request != null){
$request.abort();
$request = null;
}
$request = $.ajax({
type : "POST", //TODO: Must be changed to POST
url : "yourfile.php",
data : "data"
}).done(function(msg) {
alert(msg);
});
But it is much better if you check an if statement to check whether the ajax request is null or not.
Just call xhr.abort() whether it's jquery ajax object or native XMLHTTPRequest object.
example:
//jQuery ajax
$(document).ready(function(){
var xhr = $.get('/server');
setTimeout(function(){xhr.abort();}, 2000);
});
//native XMLHTTPRequest
var xhr = new XMLHttpRequest();
xhr.open('GET','/server',true);
xhr.send();
setTimeout(function(){xhr.abort();}, 2000);
You can abort any continuous ajax call by using this
<input id="searchbox" name="searchbox" type="text" />
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
var request = null;
$('#searchbox').keyup(function () {
var id = $(this).val();
request = $.ajax({
type: "POST", //TODO: Must be changed to POST
url: "index.php",
data: {'id':id},
success: function () {
},
beforeSend: function () {
if (request !== null) {
request.abort();
}
}
});
});
</script>
As many people on the thread have noted, just because the request is aborted on the client-side, the server will still process the request. This creates unnecessary load on the server because it's doing work that we've quit listening to on the front-end.
The problem I was trying to solve (that others may run in to as well) is that when the user entered information in an input field, I wanted to fire off a request for a Google Instant type of feel.
To avoid firing unnecessary requests and to maintain the snappiness of the front-end, I did the following:
var xhrQueue = [];
var xhrCount = 0;
$('#search_q').keyup(function(){
xhrQueue.push(xhrCount);
setTimeout(function(){
xhrCount = ++xhrCount;
if (xhrCount === xhrQueue.length) {
// Fire Your XHR //
}
}, 150);
});
This will essentially send one request every 150ms (a variable that you can customize for your own needs). If you're having trouble understanding what exactly is happening here, log xhrCount and xhrQueue to the console just before the if block.
I was doing a live search solution and needed to cancel pending requests that may have taken longer than the latest/most current request.
In my case I used something like this:
//On document ready
var ajax_inprocess = false;
$(document).ajaxStart(function() {
ajax_inprocess = true;
});
$(document).ajaxStop(function() {
ajax_inprocess = false;
});
//Snippet from live search function
if (ajax_inprocess == true)
{
request.abort();
}
//Call for new request
Just use ajax.abort() for example you could abort any pending ajax request before sending another one like this
//check for existing ajax request
if(ajax){
ajax.abort();
}
//then you make another ajax request
$.ajax(
//your code here
);
there is no reliable way to do it, and I would not even try it, once the request is on the go; the only way to react reasonably is to ignore the response.
in most cases, it may happen in situations like: a user clicks too often on a button triggering many consecutive XHR, here you have many options, either block the button till XHR is returned, or dont even trigger new XHR while another is running hinting the user to lean back - or discard any pending XHR response but the recent.
The following code shows initiating as well as aborting an Ajax request:
function libAjax(){
var req;
function start(){
req = $.ajax({
url: '1.php',
success: function(data){
console.log(data)
}
});
}
function stop(){
req.abort();
}
return {start:start,stop:stop}
}
var obj = libAjax();
$(".go").click(function(){
obj.start();
})
$(".stop").click(function(){
obj.stop();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" class="go" value="GO!" >
<input type="button" class="stop" value="STOP!" >
If xhr.abort(); causes page reload,
Then you can set onreadystatechange before abort to prevent:
// ↓ prevent page reload by abort()
xhr.onreadystatechange = null;
// ↓ may cause page reload
xhr.abort();
I had the problem of polling and once the page was closed the poll continued so in my cause a user would miss an update as a mysql value was being set for the next 50 seconds after page closing, even though I killed the ajax request, I figured away around, using $_SESSION to set a var won't update in the poll its self until its ended and a new one has started, so what I did was set a value in my database as 0 = offpage , while I'm polling I query that row and return false; when it's 0 as querying in polling will get you current values obviously...
I hope this helped
I have shared a demo that demonstrates how to cancel an AJAX request-- if data is not returned from the server within a predefined wait time.
HTML :
<div id="info"></div>
JS CODE:
var isDataReceived= false, waitTime= 1000;
$(function() {
// Ajax request sent.
var xhr= $.ajax({
url: 'http://api.joind.in/v2.1/talks/10889',
data: {
format: 'json'
},
dataType: 'jsonp',
success: function(data) {
isDataReceived= true;
$('#info').text(data.talks[0].talk_title);
},
type: 'GET'
});
// Cancel ajax request if data is not loaded within 1sec.
setTimeout(function(){
if(!isDataReceived)
xhr.abort();
},waitTime);
});
This is my implementation based on many answers above:
var activeRequest = false; //global var
var filters = {...};
apply_filters(filters);
//function triggering the ajax request
function apply_filters(filters){
//prepare data and other functionalities
var data = {};
//limit the ajax calls
if (activeRequest === false){
activeRequest = true;
}else{
//abort if another ajax call is pending
$request.abort();
//just to be sure the ajax didn't complete before and activeRequest it's already false
activeRequest = true;
}
$request = $.ajax({
url : window.location.origin + '/your-url.php',
data: data,
type:'POST',
beforeSend: function(){
$('#ajax-loader-custom').show();
$('#blur-on-loading').addClass('blur');
},
success:function(data_filters){
data_filters = $.parseJSON(data_filters);
if( data_filters.posts ) {
$(document).find('#multiple-products ul.products li:last-child').after(data_filters.posts).fadeIn();
}
else{
return;
}
$('#ajax-loader-custom').fadeOut();
},
complete: function() {
activeRequest = false;
}
});
}

Post [object%20HTMLInputElement] 404 not found on $.ajax submit

I am having a slight issue trying to implement smoothState.js (https://github.com/miguel-perez/smoothState.js) with my JSP backend.
I get this error when I try to submit the form for the first time. The second time I press submit it goes through, I have no idea what is the cause of it but found a possible clue.
POST http://localhost:8080/internal/inquiry/[object%20HTMLInputElement] 404 (Not Found)
It only happens on the forms that have a hidden input with name="action". For example if I have this in my form:
<input type="hidden" name="action" value="<%=Inquiry.CREATE_ACTION_DESCRIPTION_DATA%>" />
This is the code for my submit.
$(document).ready(function(){
$('#descriptionData').parsley().on('form:success', function() {
var $form = $("#descriptionData");
var action = "<%=Inquiry.CREATE_ACTION_DESCRIPTION_DATA%>";
var formUrl = '/inquiry.do?action=' + action + '&ajax=1';
$form.submit(function (ev) {
$.ajax({
type : "POST",
url : formUrl,
data : $form.serializeArray(),
async : true,
success : function(data) {
var smoothState = $('#main-cont').smoothState().data('smoothState');
smoothState.load(data.redirectPage);
}
});
ev.preventDefault();
});
});
});
Any help would be appreciated.
EDIT: Additional photos
Response on first submit
Response on second submit
it would be great to see some jsp code, but now my guess is that if #descriptionData is actual from, then you'd better be using just $form.serialize() to send data

Ajax, add to database and update div content

Okay, so I am trying to use ajax. I've tried several ways of doing this but nothing is working for me. I believe the main problem I have is that ajax won't add to my database, the rest is managable for me.
Here is the relevant ajax-code:
$(document).ready(function(){
console.log($("going to attach submit to:","form[name='threadForm']"));
$("form[name='threadForm']").on("submit",function(e){
e.preventDefault();
var message = $("#message").val();
//assumming validate_post returns true of false(y)
if(!validatepost(message)){
console.log("invalid, do not post");
return;
}
console.log("submitting threadForm");
update_post(message);
});
});
function update_post(message){
var dataString = "message=" + message;
alert(dataString);
$.ajax({
url: 'post_process.php',
async: true,
data: dataString ,
type: 'post',
success: function() {
posts();
}
});
}
function posts(){
console.log("getting url:",sessionStorage.page);
$.get(sessionStorage.page,function(data){
$("#threads").html(data);
});
}
function validatepost(text){
$(document).ready(function(){
var y = $.trim(text);
if (y==null || y=="") {
alert("String is empty");
return false;
} else {
return true;
}
});
}
Here is the post_process.php:
<?php
// Contains sessionStart and the db-connection
require_once "include/bootstrap.php";
$message = $con->real_escape_string($_POST["message"]);
if (validateEmpty($message)){
send();
}
function send(){
global $con, $message;
$con->create_post($_SESSION['username'], $_SESSION['category'], $_SESSION("subject"), $message);
}
//header("Location: index.php");
?>
And lastly, here is the html-form:
<div id="post_div">
<form name="threadForm" method="POST" action="">
<label for="message">Meddelande</label><br>
<textarea id="message" name="message" id="message" maxlength="500">
</textarea><br>
<input type="submit" value="Skicka!" name="post_btn" id="post_btn"><br>
</form>
create_post is a function I've written, it and everything else worked fine until I introduced ajax.
As it is now, none of the console.log:S are getting reached.
Ajax works when jumping between pages on the website but the code above literally does nothing right now. And also, it works if I put post_process.php as the form action and don't comment out the header in post_process-php.
I apologize for forgetting some info. I am tired and just want this to work.
I would first test the update_post by removing the button.submit.onclick and making the form.onsubmit=return update_post. If that is successful place the validate_post in the update_post as a condition, if( !validate_post(this) ){ return false;}
If it's not successful then the problem is in the php.
You also call posts() to do what looks like what $.get would do. You could simply call $.get in the ajax return. I'm not clear what you are trying to accomplish in the "posts" function.
First you can just submit the form to PHP and see if PHP does what it's supposed to do. If so then try to submit using JavaScript:
$("form[name='threadForm']").on("submit",function(e){
e.preventDefault();
//assumming validate_post returns true of false(y)
if(!validate_post()){
console.log("invalid, do not post");
return;
}
console.log("submitting threadForm");
update_post();
});
Press F12 in Chrome or firefox with the firebug plugin installed and see if there are any errors. The POST should show in the console as well so you can inspect what's posted. Note that console.log causes an error in IE when you don't have the console opened (press F12 to open), you should remove the logs if you want to support IE.
Your function posts could use jQuery as well as it makes the code shorter:
function posts(){
console.log("getting url:",sessionStorage.page);
$.get(sessionStorage.page,function(data){
$("#threads").html(data);
});
}
UPDATE
Can you console log if the form is found when you attach the event listener to it?
console.log($("going to attach submit to:","form[name='threadForm']"));
$("form[name='threadForm']").on("submit",function(e){
....
Then set the action of the form to google.com or something to see if the form gets submitted (it should not if the code works). Then check out the console to see the xhr request and see if there are any errors in the request/responses.
Looking at your code it seems you got the post ajax request wrong.
function update_post(message){
console.log(message);
$.ajax({
url: 'post_process.php',
async: true,
//data could be a string but I guess it has to
// be a valid POST or GET string (escape message)
// easier to just let jQuery handle this one
data: {message:message} ,
type: 'post',
success: function() {
posts();
}
});
UPDATE
Something is wrong with your binding to the submit event. Here is an example how it can be done:
<!DOCTYPE html>
<html>
<head>
<script src="the jquery library"></script>
</head>
<body>
<form name="threadForm" method="POST" action="http://www.google.com">
<label for="message">Meddelande</label><br>
<textarea id="message" name="message" id="message" maxlength="500">
</textarea><br>
<input type="submit" value="Skicka!" name="post_btn" id="post_btn"><br>
</form>
<script>
$("form[name='threadForm']").on("submit",function(e){
e.preventDefault();
console.log("message is:",$("#message").val());
});
</script>
</body>
</html>
Even with message having 2 id properties (you should remove one) it works fine, the form is not submitted. Maybe your html is invalid or you are not attaching the event handler but looking at your updated question I think you got how to use document.ready wrong, in my example I don't need to use document.ready because the script accesses the form after the html is loaded, if the script was before the html code that defines the form you should use document ready.

in ajax form do validation and show a hidden div

I have this function(to make my form work with ajax):
$(function() {
$('#restore_form').ajaxForm({
beforeSubmit: ShowRequest,
success: SubmitSuccesful,
error: AjaxError
});
});
function ShowRequest(formData, jqForm, options) {
var queryString = $.param(formData);
alert('BeforeSend method: \n\nAbout to submit: \n\n' + queryString);
return true;
}
function AjaxError() {
alert("An AJAX error occured.");
}
function SubmitSuccesful(responseText, statusText) {
alert("SuccesMethod:\n\n" + responseText);
}
my form(django form) only contains a file upload field. i want also check validation and i have this function for this purpose:
function TestFileType( fileName, fileTypes ) {
if (!fileName) {
alert("please enter a file");
return false;
}
dots = fileName.split(".")
fileType = "." + dots[dots.length-1];
if(fileTypes.join(".").indexOf(fileType) != -1){
alert('That file is OK!') ;
return true;
}
else
{
alert("Please only upload files that end in types: \n\n" + (fileTypes.join(" .")) + "\n\nPlease select a new file and try again.");
return false;
}
}
now when i try to use validation function(TestFileType) in the first function, it doesn't work. both of them works seperately. fore example if i write the below line in onclick of submit button, it works:
onclick="TestFileType(this.form.file.value, ['tar.gz']);"
I also want instead of alerting user, show a hidden div in success function:
i have:
and i want in success function do:
$('.response').html(responseText);
$('.response').show();
EDIT:
Here is my template:
<form id="restore_form" enctype="multipart/form-data" method="POST" action="restore/">
{{ form.non_field_errors }}
{{ form.as_p }}
{{ form.file.errors }}
<p id="sendwrapper"><input type="submit" value="{% trans "Send" %}" id="submitButton" style="margin-bottom:10px; cursor:pointer; background-color:#F90;"/></p>
</form>
<div class="response" style="display: none;"></div>
but it doesn't work! it seems only alert works in this function. Can you please help me?
really thanks :)
I've attempted to use the AjaxForm plugin in the past and found that unless you have a very specific reason to use it, it's typically easier to write the ajax form submit code without the plugin. This is a simplified/commented version of a previous jquery ajaxform that I created using Jquery without the plugin:
$('form').submit(function(event) {
var form = $(this);
// creates a javascript object of the form data
// which can be used to validate form data
var formArray = form.serializeArray();
// (validate whatever values in formArray you need to check here);
if (form_is_valid) {
var formData = form.serialize(); // a URL-encoded version of the form data for the ajax submission
$.ajax({
type: "POST",
url: someUrl,
data: formData,
success: function(data) {
// update success message boxes here
}
});
} else {
// update client-side validation error message boxes
}
event.preventDefault(); // prevent the form from actually navigating to the action page
});
Hopefully this helps, I've found that the plugin can be useful at times, however I've typically found that this leads to easier to understand code and avoids the use of plugins..

check if image is valid before uploading-- mootools

I'm using mootools request to push image data to a server to import images. My question is how to determine if an image path is valid before completing the request?
Here's what I have now--
http://jsfiddle.net/sTbFb/1/
function doUpload(){
var remoteFile = document.id('uploadRemote').get('value');
var imageRequest = new Request({
url:'index.php',
method: 'post',
data: 'path='+remoteFile,
onRequest: function() {
console.log(remoteFile);
var myimage = Asset.image(remoteFile,
{
//onError: imageRequest.cancel() // <-- this doesn't work either
onError: this.cancel()
}
);
},
onSuccess: function(response) {
alert(response);
}
}).send();
}
document.id('submit').addEvent('click', function(){
doUpload();
});
I'm trying to use Asset.image to test if a path is truly an image-- then if it's not, to cancel the request. However, it's not working out.
Any hints on what I'm doing wrong? Thanks!
You can't get the path to the selected file from an <input type="file" />. So, you won't be able to load it before you upload it. The best you can do is to check the file extension.
Edit: Perhaps the problem is with this line:
onError: this.cancel()
It should be:
onError: function () {
imageRequest.cancel();
}

Categories