AJAX always fails after some time - javascript

I tried everything and searched everywhere but i can't wrap my head around this...
I have a button in a form that triggers on click a javascript function, which in turn makes an AJAX request to my server.
The problem is no matter what i do the request is made but the .fail method always executes after a few seconds and i get no error. I am sure my server sends no response (it's a server on an ESP32 which relies on the ESPAsyncWebServer, code below) and to add to this, the network inspector on both Firefox and Safari shows no communication.
I tried all sorts of things, from adding timeout:0 and cache:false to the AJAX call, to changing to GET instead of POST as the AJAX method, as well as preventing the default event on the button by returning false or using .preventDefault() in the javascript function but nothing works. What am I missing?
Here's the HTML:
<form>
<div class="form-row align-items-center mt-4">
<div class="form-group col-md-8">
<label for="newCode">Codice</label>
<div class="input-group">
<input type="text" class="form-control" id="newCode" placeholder="12345678">
<div class="input-group-append">
<button type="button" class="btn btn-secondary" id="learnCodeButton" onclick="learnNewCode(); return false;">Rileva</button>
</div>
</div>
</div>
<div class="form-group col-md-4">
<label for="newAlarmTriggerDelay">Delay Allarme (s)</label>
<input type="text" class="form-control" id="newAlarmTriggerDelay" placeholder="60">
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label for="newDescription">Descrizione</label>
<input type="text" class="form-control" id="newDescription" placeholder="Studio Interno">
</div>
</div>
<div class="d-flex justify-content-center">
<button type="submit" id="saveSensor" onclick="saveSensor()" class="btn btn-lg btn-primary mt-4 pl-5 pr-5">Salva</button>
</div>
<div class="d-flex justify-content-center">
<button type="button" id="removeSensor" onclick="removeSensor()" class="btn btn-lg btn-link mt-2 text-danger">Rimuovi</button>
</div>
</form>
the javascript function:
function learnNewCode() {
document.getElementById("learnCodeButton").className = "btn btn-warning";
$.ajax({
method: "POST",
url: "/learnCode",
dataType: "json",
})
.done(function(returnedData) {
//substituteInField("newCode", returnedData["newCode"]);
})
.fail(function(jqXHR, textStatus, errorThrown) {
//substituteInField("newCode", "Learn code failed - Retry");
console.log("jqXHR response: " + jqXHR.responseText);
console.log("Status: " + textStatus);
console.log("Error: " + errorThrown);
}).always(function() {
document.getElementById("learnCodeButton").className = "btn btn-secondary";
});
}
the code on the ESP32:
server.on("/learnCode", HTTP_POST, [](AsyncWebServerRequest * request) {
Serial.println("POST /learnCode");
});
and finally the console log (Firefox):
XHR POST http://192.168.1.105/learnCode
jqXHR response: undefined
Status: error
Error:
Thank you for your help.

You are not sending a response from your ESP32 Server.
The client is probably timing out.
Try adding a response (Note the response type here is text/plain adjust accordingly).
server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", "Post route");
});

So i actually solved this with some help... the fact is that the timeout option in the AJAX request refers to the receipt of the request by the server and not to the time that the server takes to send a response.
To explain this better, when the AJAX request is sent to the server, the server acknowledges the receipt of the request to the client. The time between the request being made and the server acknowledging its receipt is what can be regulated by the timeout option.
After acknowledging the receipt, if the server doesn't serve a response in less than a few seconds, the AJAX call fails.
In my case, the ESPAsyncWebServer probably acknowledges the receipt before calling the server.on() method so if I send no response or the response takes too much time to deliver the AJAX call fails. In fact, if i load the website, power off the ESP, and after that try to make the call it won't fail but wait endlessly, as the timeout is by default infinite.
The solution will probably be send a call to activate the methods i need on the ESP and then poll the server periodically until i get an answer.

Related

Roku remote in javascript

I am get errors in the web console for my roku remote control script. The javascript is as shown here:
<script>
function rokuSend(RokuAccess) {
xhr = new XMLHttpRequest();
xhr.onload=function() { alert(xhr.responseText); }
xhr.open("POST", RokuAccess);
xhr.send();
}
function rokuKeySend(keyVal) {
rokuSend("http://" + document.getElementById('RokuIP').value + ":8060/keypress/" + keyVal);
}
I supply the IP address for the Roku using:
<form id="Roku"><input type="text" id="RokuIP"></form>
When ever I press a key on my web based remote it send a command, to simplify things I will be using the SAME function to send key presses as well as other commands. So one of the functions called "rokuKeySend()" simply constructs the proper string that is needed to send a command issued by a key press. The second function "rokuSend()"sends the command to the Roku. Later additional commands will be sent to collect data from the Roku so I will create more functions that use "rokuSend()". For now I use the following buttons (these will later be replaced with images), for now they work fine as proof of concept:
<button type="button" onclick="rokuKeySend('Back')">Back</button>
<button type="button" onclick="rokuKeySend('Home')">Home</button>
<button type="button" onclick="rokuKeySend('Up')">Up</button>
<button type="button" onclick="rokuKeySend('Left')">Left</button>
<button type="button" onclick="rokuKeySend('Select')">Select</button></td>
<button type="button" onclick="rokuKeySend('Right')">Right</button>
<button type="button" onclick="rokuKeySend('Down')">Down</button>
<button type="button" onclick="rokuKeySend('InstantReplay')">InstantReplay</button>
<button type="button" onclick="rokuKeySend('Info')">Info</button>
<button type="button" onclick="rokuKeySend('Rev')">Rev</button>
<button type="button" onclick="rokuKeySend('Play')">Play</button>
<button type="button" onclick="rokuKeySend('Fwd')">Fwd</button>
<button type="button" onclick="rokuKeySend('Backspace')">Backspace</button>
<button type="button" onclick="rokuKeySend('Search')">Search</button>
<button type="button" onclick="rokuKeySend('Enter')">Enter</button>
After placing the IP into the input of the form, I can press ANY of the buttons and they do work. However they 'visually' depress when clicked by a mouse, but do not return from the depressed state. Upon checking the web console of the browser I found an error. This error is likely the reason I do not get return from the depressed state. How do I fix this? The error is listed below:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://xxx.xxx.xxx.xxx/keypress/KEY. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
In the above error 'xxx' represents the IP and 'key' represents the key that was pressed.
Its mentioned in the error, CORS Header is missing. Cross Object Resource Sharing(CORS) requires to add header "Access-Control-Allow-Origin" in the request. You can try to add this header in the request-
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
If its not working, you have to create something proxy kind of solution. You can find more details here and here regarding CORS and fixing the error.

PHP and JQuery ajax url

I am using a ready booking form source code and I would like to make some changes according to our needs.
I quote below the source code that is important to be seen and not the whole source code of the file. I would like to execute, as soon as a button is clicked, a mysqli_query to update variables on the database. So, I am trying to use Jquery and AJAX to make this happen.
The code below shows a button Check Availability already defined which executes Javascript code and I added also my button "Book Now" and I would like to run also my code. See the code below:
<form id="bsSearchForm_<?php echo $_GET['index'];?>" action="<?php echo PJ_INSTALL_URL; ?>index.php?controller=pjFront&action=pjActionCheck" method="post" >
<div class="row ">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6 col-xss-12">
<div class="form-group">
<label for="address">Pickup Address</label>
<input type="text" class="form-control" name="pickup" placeholder="Enter a location">
</div>
</div>
<div class="form-group pjBsFormActions">
<button type="submit" class="btn btn-primary"><?php echo("Check Availability"); ?></button>
<button type="submit" class="btn btn-primary" onclick="checkClicked()"><?php echo("Book Now"); ?></button>
</div><!-- /.form-group pjBsFormActions -->
</div>
</form>
Now at the same php file at the beginning I have defined this source code:
<script>
function checkClicked() {
$.ajax({
url: "test.php",
type: 'POST',
dataType: 'html'
});
}
</script>
So, I would like to run my own PHP source code at an external php file like test.php and get the input field data from "pickup" and perform a mysqli_query on database.
However the code at test.php file is not executed at all. I think that the problem is the form action parameter <?php echo PJ_INSTALL_URL; ?>index.php?controller=pjFront&action=pjActionCheck. How could I find this file(a lot of source files) and maybe place the source code there?
Or should I have to define the new button differently and so I would be able to call my own PHP file at any directory?
The AJAX URL parameter should be a relative or absolute path to the test.php file? Where should I create the test.php file at my directories?
Please help me find a quick solution to my issue.
This very easy and simple
1. Create an html page with the form like.
<form id="sample">
//some thing here....
<input type="submit" class="btn btn-success" name="submit" value="Create" id="sample">
</form>
2. Create an Js page like this.
//click function
$("#sample").click(function(event) {
sample();
});
//ajax function here
function sample(){
$.ajax({
url: '/path/to/file',
type: 'GET/POST',
dataType: 'default: Intelligent Guess (Other values: xml, json, script, or html)',
data: {
param1: 'value1'
},
success:function(result){
alert(result);
}
})
.done(function() {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
}
3. Create an php script file.
add the actual path in directory like if you are using the localhost example: public/script/test.php then the ajax path is ../script/test.php
4. the javascript link to the the html page like
example:
<script type="text/javascript" src="sample.js"></script>
you need to create test.php on same directory where your form's file is created.
If you have a submit-Button the form will be submitted with the action you defined and not with the onclick-event. For that to work you have to simply replace it with
<button type="button"

Form validate PreventDefault works only locally but not on the server

I try to submit a form with ajax, and with the jquery validate() function. When I test it locally, the event.preventDefault() works! Also without the line "event.preventDefault();" but, when I deploy it to the server, the result json loads in a new page - it doesen't prevent the redirect.
$(function () {
$("#photo-form").validate({
submitHandler: function (form, event) {
event.preventDefault(); //with or without - doesn't work
if ($(form)[0].checkValidity()) {
console.log("No Errors!")
var formData = new FormData(document.querySelector("#photo-form"));
var photo = formData.get("photo");
$.ajax({
url: "/photo/",
type: 'POST',
data: formData,
async: false,
success: function (data) {
console.log("Ajax success");
if (data.error == "OK") {
alert("Photo was uploaded");
} else {
//error
}
},
error: function (data) {
},
cache: false,
contentType: false,
processData: false
});
return false; //this also doesn't help
}
}
});
});
Where is the error in this case? What is the difference between local and server for this code?
HTML form:
<form id="photo-form" action="/photo/" method="post" enctype="multipart/form-data"
class="row col s10 center-block">
<div class="card row">
<div class="col s12">
<h5>Generic Information</h5>
<div class="input-field col s12 m6">
<i class="material-icons prefix">title</i>
<input id="campaign_id" type="text" name="campaign_id" class="validate" required>
<label for="campaign_id" data-error="huh?" data-success="WOW!">campaign_id</label>
</div>
<div class="input-field col s12 m6">
<div class="file-field input-field">
<button class="btn btn-floating pink lighten-1 file-btn">
<span>Photo</span>
<input name="photo" type="file">
</button>
<div class="file-path-wrapper">
<input class="file-path validate" type="text">
</div>
</div>
</div>
<div class="row">
<div class="input-field col s8">
<button class="btn-large waves-effect waves-light" type="submit">Submit
<i class="material-icons right">send</i>
</button>
</div>
</div>
</div>
</div>
</form>
It might be since your are trying to load jquery libs with HTTP while your session is with HTTPS. Make sure you are loading jquery with https://
Check the javascript files include into the View. If you was using the Bundle to manage css & js libraries, you may try to include that by normal way with script, link tag.
In the past, I have same problem with you after deploy my app to the webserver.
Hope this help.
Form validate PreventDefault works only locally but not on the server
Technically, it does not matter where the code is hosted, .preventDefault() is JavaScript and always/only works locally (client-side) in the browser. So your problem is elsewhere... i.e. broken JavaScript after uploading to server.
Despite your testing, you have some mistakes within your code:
submitHandler: function(form, event) { ...
You cannot invent arguments to pass into a callback provided by the plugin's developer. He simply gives you the form argument, and that is all. The event argument is meaningless here and will be ignored.
event.preventDefault() will be ignored. See item #1; the event argument has no meaning in this context.
You do not need event.preventDefault() in the first place. The plugin automatically handles capturing the click and blocking the default submit action, internally.
if ($(form)[0].checkValidity()) { ...
Presumably you're checking to see if the form passes validation before allowing your ajax submission. This too is completely unnessary. By definition, the submitHandler only fires when the form is already valid.
Also, checkValidity() is tied into HTML5 validation, which is totally disabled by the jQuery Validate plugin when it's initialized. At best, this would do nothing, however, you should remove it.
(It's a moot point, but you also would not need the [0] since the $(form) selector is using the form argument as provided by the plugin.)
In your local testing you have nothing breaking the plugin or preventing it from operating normally. Since the plugin already prevents the default submit automatically, you falsely believe that your .preventDefault() is doing something. After deployment, you falsely believe that your .preventDefault() suddenly stops working, when instead the entire plugin is broken likely due to some reason bulleted below.
If the plugin is not blocking your default form submit action, then likely you have one or more of these conditions:
jQuery and/or jQuery Validate plugin not properly included
Error(s) blocking execution of your JavaScript
Improper declaration of validation rules causing form to appear valid
HTML markup issue(s) (bad selector(s), etc.) preventing initialization of the plugin on your form element
Invalid HTML, such as duplicate id, etc.
Some other issue preventing proper initialization of the plugin
Working:
$(function () {
$("#photo-form").validate({
submitHandler: function(form) {
console.log("No Errors!");
console.log("form data: " + $(form).serialize());
$.ajax({
....
});
return false;
}
});
});
DEMO: jsfiddle.net/b9x4626a/

JSON data not showing up when I change http.jsonp() URL

I'm trying to read data from an external JSON file using AngularJS.
Here is my HTML
<div class="panel panel-default" ng-controller="MyAppController">
<div class="panel-heading">
<div class="input-group">
<input ng-model="query" type="text" placeholder="What file are you looking for?" class="form-control"><span ng-click="clearFilter()" ng-disabled="query.length == 0" class="input-group-addon"><i class="glyphicon glyphicon-remove"></i></span>
</div>
</div>
<div class="panel list-group">
<span data-ng-repeat="cat in cats | filter: query" class="list-group-item animate-repeat">{{cat.title}}
</span>
<div class="clearfix"></div>
</div>
</div>
It works fine when I use this in my JS file and data shows up in a list.
function MyAppController($scope, $http) {
var url = 'http://jobs.github.com/positions.json?callback=JSON_CALLBACK';
$http.jsonp(url).success(function(data) {
$scope.cats = data;
});
}
But when I change the URL to my personal site nothing shows up even though I literally just copied and pasted everything in the github JSON file to a local JSON file. (just to test it out)
function MyAppController($scope, $http) {
var url = 'http://ciagent.com/Website-files/positions.json?callback=JSON_CALLBACK';
$http.jsonp(url).success(function(data) {
$scope.cats = data;
});
}
http://ciagent.com/Website-files/positions.json?callback=JSON_CALLBACK &
http://jobs.github.com/positions.json?callback=JSON_CALLBACK have the same exact content but only the github one works with my angular app for some reason.
Any reasons as to why it's doing this?
Assuming you are using a static resource file you need to realize that the string 'JSON_CALLBACK' is a placeholder and gets modified within each $http.jsonp() request to something else.
You should be able to see this in the actual request URL in network tab of browser dev tools.
You can also open the github version in browser and change the value to see that it is not static on their server and will adjust to whatever value is sent.
If you want to use jsonp server side it needs to return dynamic value of the callback GET parameter value.
+1 to what #charlietfl said. Also, be sure to set Content-Type:application/javascript;charset=utf-8 in your response headers.

Blueimp jquery file upload plugin throwing error after uploading 100% is done to rackspace cloud storage

I have been trying to upload files to rackspace storage from my website. I have followed the following api guide to create the form to upload files to rackspace.
http://docs.rackspace.com/files/api/v1/cf-devguide/content/FormPost-d1a555.html
section 7.2, 7.2.1 and 7.2.2
It completely works fine if I do a normal form submit. The file gets uploaded to rackspace storage and returns a status 201 and a blank message. I checked the file in the container and its uploaded successfully.
But now the problem comes when i try to integrate progressbar using Blueimp jQuery file upload plugin.
Here's my code to initialize the fileupload plugin
$(function () {
'use strict';
// Initialize the jQuery File Upload widget:
$('#fileupload').fileupload({maxChunkSize: 10000000});
if (window.location.hostname === 'blueimp.github.com') {
// Demo settings:
$('#fileupload').fileupload('option', {
url: '//jquery-file-upload.appspot.com/',
maxFileSize: 5000000,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
process: [
{
action: 'load',
fileTypes: /^image\/(gif|jpeg|png)$/,
maxFileSize: 20000000 // 20MB
},
{
action: 'resize',
maxWidth: 1440,
maxHeight: 900
},
{
action: 'save'
}
]
});
// Upload server status check for browsers with CORS support:
if ($.support.cors) {
$.ajax({
url: '//jquery-file-upload.appspot.com/',
type: 'HEAD'
}).fail(function () {
$('<span class="alert alert-error"/>')
.text('Upload server currently unavailable - ' +
new Date())
.appendTo('#fileupload');
});
}
} else {
// Load existing files:
console.log("mukibul");
$('#fileupload').each(function () {
var that = this;
console.log("result1");
$.getJSON(this.action, function (result) {
if (result && result.length) {
console.log("result");
console.log(result);
$(that).fileupload('option', 'done')
.call(that, null, {result: result});
}
});
});
}});
Here's the web form to upload files
<form id="fileupload" action="https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_4d6c7b53-7b5a-458c-8a2d-957971f293bb/tranceyatralocal/${sessionScope.tyUser.userID}/${albumDetails.albumId}" method="POST" enctype="multipart/form-data">
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
<input type="hidden" name="redirect" value="http://localhost:8080/impianlabs/home/uploadResponse.htm" />
<input type="hidden" name="max_file_size" value="${max_file_size}" />
<input type="hidden" name="max_file_count" value="10" />
<input type="hidden" name="expires" value="${expires}" />
<input type="hidden" name="signature" value="${hmac}" />
<div class="row fileupload-buttonbar" style="margin:10px;">
<div class="span7" style="">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-success fileinput-button">
<i class="icon-plus icon-white"></i>
<span>Add files...</span>
<input type="file" name="files[]" multiple>
</span>
<button type="submit" class="btn btn-primary start">
<i class="icon-upload icon-white"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning cancel">
<i class="icon-ban-circle icon-white"></i>
<span>Cancel upload</span>
</button>
<button type="button" class="btn btn-danger delete">
<i class="icon-trash icon-white"></i>
<span>Delete</span>
</button>
<input type="checkbox" class="toggle">
</div>
<!-- The global progress information -->
<div class="span5 fileupload-progress fade">
<!-- The global progress bar -->
<div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
<div class="bar" style="width:0%;"></div>
</div>
<!-- The extended global progress information -->
<div class="progress-extended"> </div>
</div>
</div>
<!-- The loading indicator is shown during file processing -->
<div class="fileupload-loading"></div>
<br>
<!-- <div>
<ul id="filePreview">
</ul>
</div> -->
<!-- The table listing the files available for upload/download -->
<table role="presentation" class="table table-striped"><tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"></tbody></table>
</form>
When I upload any files, it starts uploading normally, the progress starts showing up as expected. In chrome Inspect->Network tabs I could see two requests to the rackspace server. One is method OPTIONS which returns 200 and another is method POST which remains in Pending until the progress bar reaches 100% but as soon as it reaches 100% the status of the POST method changes to cancelled and the jquery file upload plugin prints error true in the webpage. I am not able to understand why the plugin is throwing error. I checked the container and found that the file got uploaded successfully.
I have used curl to set all headers required for CORS in rackspace. But not sure what I am doing wrong. Any help to resolve the issue would be appreciated.
Note: I'm using spring mvc for the application.
Thanks,
Mukibul
At the present time, Cloud Files and the underlying Openstack Swift component do support POST uploading as you've been successful with (Docs here and here). Unfortunately there appears to be a known issue that prevents CORS from working properly due to a missing header in the response.
The change has been merged into master, but hasn't been deployed to Rackspace's running version for Cloud Files. I have an inquiry in with our CF team on a timeline for having this fixed so we can come to a real resolution for this.
UPDATE: The script fails to upload for me in Chrome, but works in Firefox. Chrome reports the POST is cancelled as you described, but Firefox completes it and gets an HTTP 303 response along with the expected redirect URI and the file is present in the container. I'm looking at the code for the plugin to see how it handles success/failure in it's responses.
Just found out from the Rackspace that this merge is not in the roadmap and is also not being tested currently. I don't see this coming in near future.
Hopefully one day they will implement it. For now, I would just overwrite the header of the page in the controller before serving it to the browser.

Categories