I'm looking to setup a web page that samples data via AJAX calls from an embedded web-server. How would I set up the code so that one request doesn't overlap another?
I should mention I have very little JavaScript experience and also a compelling reason not to use external libraries of any size bigger than maybe 10 or so kilobytes.
You may want to consider the option of relaunching your AJAX request ONLY after a successful response from the previous AJAX call.
function autoUpdate()
{
var ajaxConnection = new Ext.data.Connection();
ajaxConnection.request(
{
method: 'GET',
url: '/web-service/',
success: function(response)
{
// Add your logic here for a successful AJAX response.
// ...
// ...
// Relaunch the autoUpdate() function in 5 seconds.
setTimeout(autoUpdate, 5000);
}
}
}
This example uses ExtJS, but you could very easily use just XMLHttpRequest.
NOTE: If you must have an exact interval of x seconds, you would have to keep track of the time passed from when the AJAX request was launched up to the setTimeout() call, and then subtract this timespan from the delay. Otherwise, the interval time in the above example will vary with the network latency and with the time to processes the web service logic.
I suggest you use a small toolkit like jx.js (source). You can find it here: http://www.openjs.com/scripts/jx/ (less than 1k minified)
To setup a request:
jx.load('somepage.php', function(data){
alert(data); // Do what you want with the 'data' variable.
});
To set it up on an interval you can use setInterval and a variable to store whether or not a request is currently occuring - if it is, we simple do nothing:
var activeRequest = false;
setInterval(function(){
if (!activeRequest) {
// Only runs if no request is currently occuring:
jx.load('somepage.php', function(data){
activeRequest = false;
alert(data); // Do what you want with the 'data' variable.
});
}
activeRequest = true;
}, 5000); // Every five seconds
AJAX, despite the name, need not be asynchronous.
Here is the asynchronous method...
var req;
function ajax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
...but here is a synchronous equivalent...
function sjax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.open(method, url, false);
req.send(payload);
action();
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, false);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
... and here is a typical action ...
function insertHtml(target)
{
var pageTarget = arguments[0];
if (req.readyState == 4) // 4 == "loaded"
{
if (req.status == 200) // 200 == "Ok"
{
if (req.responseText.indexOf("error") >= 0)
{
alert("Please report the following error...");
pretty = req.responseText.substring(req.responseText.indexOf("error"),1200);
pretty = pretty.substring(0,pretty.indexOf("\""));
alert(pretty + "\n\n" + req.responseText.substring(0,1200));
}
else
{
div = document.getElementById(pageTarget);
div.innerHTML = req.responseText;
dimOff();
}
}
else
{
alert("Could not retreive URL:\n" + req.statusText);
}
}
}
Related
There is an external website which contains an html document for each day of the year, and I am trying to automatically load the document for the current date. However, the urls are not consistent across every document. Some of them end with .html while others end with .htm, and some of them might have a letter appended to the filename.
What I want to do is attempt to load a url, and if it results in a 404 error, try loading a different url.
For example, I might do window.location.replace(baseurl+'.htm');
and if that results in a 404 error, attempt window.location.replace(baseurl+'.html'); and if that results in a 404, try something else.
How can I determine when the server sends a 404 error and attempt to load a new url?
Here's a function where you can pass in extensions to try, and it returns the first valid URL to a callback:
var request = new XMLHttpRequest();
var extensions = ['.html', '.htm'];
var count = 0;
var baseurl = 'http://blah.com/file';
function validUrl(baseurl, cb) {
request.open('GET', baseurl + extensions[count], true);
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
cb(baseurl + extensions[count]);
} else {
count++;
if (count === extensions.length) {
cb(false);
} else {
validUrl(baseurl, cb);
}
}
}
};
request.send();
}
// usage:
validUrl(baseurl, function(url) {
if (url) {
// use the valid url
} else {
console.log('no valid urls');
}
});
As #Siguza said you can persist as an asynchronous request and validate it's status.
I suggest you to create a function which calls an AJAX and handle it's status returning to you if it's OK or not as a boolean. Something like:
// I'm building an function to validate the URL
function checkValidURL(url) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
// code for older browsers
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// Callback
xmlhttp.onreadystatechange = function() {
if (this.status == 200) {
return true; // OK
} else { // or -> } else if (this.status == 404) {
return false; // Ops, something happen..
}
};
// AJAX configuration
xmlhttp.open("GET", url, false); // <- "false" for a synchronous request
xmlhttp.send();
}
Simple example of use:
if (!checkValidURL("http://www.my_url")) {
console.log("invalid URL");
// Call or check other URL
} else {
// It's OK, proceed with the business rules
}
Functions can wait AJAX requests by setting asynchronous "false", like: Is there any way to wait for AJAX response and halt execution?
I am using Phonegap 3.3.0 and on iOS, the following http request always returns 0, whether the file exists or not !!
var url = './images/pros/imagefile.png';
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
http.status
It returns 0 if the file exists, but if I try a fake wrong url :
var url = 'httpbabla/images/pros/imagefile.pngfkjdqmkfjdmqsl';
or
var url = 'www/images/pros/imagefidddddddle.pngooijijijiojs';
it still returns 0.
Is it a phonegap bug ? If not, then how to quickly distinguish existing local files from unexisting files with Phonegap and iOS?
Thanks
You might have better luck with an asynchronous request and onload and onerror handlers. Note the use of a true parameter as the last argument to http.open:
var url = 'file:///does/not/exist.jpg';
var http = new XMLHttpRequest();
http.open('HEAD', url, true);
http.onload = function(e){/* Success! File exists; process the response... */};
http.onerror = function(e){/* Failed - file does not exist - do whatever needs to be done... */};
http.send();
Once you call http.send your function will be done and control will return to the caller. Whatever processing you need to do on either success or failure will need to be taken care of in the onload and onerror callbacks. Take the time to learn how to use Javascript callbacks (and closures) if you're not familiar with them - they're one of the most powerful features in the language.
This works for me :
function UrlExists(url)
{
if ( isPhoneGap && isIOS() ) {
if (url.fileExists()){ //see prototype below
return true;
}else {
return false;
}
} else {
try {
http = new XMLHttpRequest();
http.open("HEAD", url, false);
http.send();
}
catch (err) {
//alert("An error:" + err.name + "---" + err.message);
}
//return http.status!=404;
if (http.readyState == 4) {
console.log("http.status="+http.status);
return http.status==200 || http.status==0;
}
}
}
// check local file existance for iOS
String.prototype.fileExists = function() {
filename = this.trim();
var response = jQuery.ajax({
url: filename,
type: 'HEAD',
async: false
}).status;
return (response != "200") ? false : true;
}
I have this code to make an ajax request, but according to Chrome Inspector the callback associated with the request is being called twice (by this I mean the response is being logged into the console twice), 2 more logs are being printed without any content. Here's the code:
var ajax = {
pull: function (settings) {
settings.type = 'get';
settings.callback = typeof (settings.callback) === 'function' ? settings.callback : false;
settings.data = settings.data ? settings.data : null;
return this.request(settings.url, settings.type, settings.callback, settings.data);
},
request: function (url, type, callback, data) {
var ids = ['MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP'],
xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
for (var i = 0; i < ids.length; i++) {
try {
xhr = new ActiveXObject(ids[i]);
break;
} catch (e) {}
}
}
if (callback) {
xhr.onreadystatechange = function () {
callback(xhr);
};
}
xhr.open(type, url, true);
if (type.toUpperCase() === 'GET') {
xhr.send();
} else if (type.toUpperCase() === 'POST') {
xhr.send(data);
}
}
}
ajax.pull({
url: 'http://localhost/my/twtools/scripts/ajax.php',
callback: function (xhr) {
console.log(xhr.response);
}
});
xhr.onreadystatechange has several steps (numbered from 0 top 4 I do believe something like 0 = uninitialized, 1 = starting etc, although I can't rember the exact names of the steps anymore, a quick google should find them), and each step is calling your callback. If I remember correctly, the last stage is 4, so I do believe you need to check something like this
if (xhr.readyState == 4 && xhr.status == 200)
{
// call has finished successfully
}
inside you callback, i.e. to check that it is all finished and got a successful response
I've been spoilt by jQuery these days (so much easier to do with jQuery), been quite a while since I wrote raw ajax
You're using onreadystatechange, which gets called more than once (once each state change).
Try using
xhr.onload = function() {
callback(xhr);
};
Please help, I have been looking at this all day and I know there must be a simple fix!
How do I pass results back to textService so that I can make a call such as
textResult = textService(text to pass in);
I don't want to use a global variable if I can avoid it.
This is the code
function textService(text){
req.open("GET", "http://....?text="+text, true);
req.onload = showResults;
req.send(null);
}
function showResults() {
results = req.responseXML.getElementsByTagName("Result");
}
Thank you in advance
function textService(text){
// set flag to false for sync requests
req.open("GET", "http://...?text="+text, false);
req.send(null);
// browser will be stalled till request is complete.
if(req.status == 200 && req.readyState == 4) {
return req.responseXML.getElementsByTagName("Result");
} else {
return 'request failed';
}
}
// javascript will stall till request is complete.
var results = textService('someText');
Note, making synchronous request can be harmful, if a request fails, it might stall the browser indefinatly. It's better to do it asynchronously.
function textService(text, callback){
// async is true by default, no need to pass 3rd param.
req.open("GET", "http://...?text="+text);
req.send(null);
req.onreadystatechange = function(){
if(this.readyState == 4 || this.status == 200) {
callback(this.responseXML);
}
}
}
textService('someText', function(xml){
// do stuff with XML.
});
Just need switch your coding mind to async programming ;)
You can use this
function showResults() {
results = this.responseXML.getElementsByTagName("Result");
}
How can I check an existence of a file (It is an xml file that I would like to check in this case) with JavaScript?
if you're using jQuery, you can try to load the file
$.ajax({
type: "GET",
url: "/some.xml",
success: function()
{ /** found! **/},
error: function(xhr, status, error) {
if(xhr.status==404)
{ /** not found! **/}
}
});
if you're not using jQuery:
function ajaxRequest(){
var activexmodes=["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
//Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
if (window.ActiveXObject){
for (var i=0; i<activexmodes.length; i++){
try{
return new ActiveXObject(activexmodes[i])
}
catch(e){
//suppress error
}
}
}
else if (window.XMLHttpRequest) // if Mozilla, Safari etc
return new XMLHttpRequest()
else
return false
}
var myrequest=new ajaxRequest()
myrequest.onreadystatechange=function(){
if (myrequest.readyState==4){ //if request has completed
if (myrequest.status==200 || window.location.href.indexOf("http")==-1){
// FOUND!
}
}
}
myrequest.open('GET', 'http://blabla.com/somefile.xml', true);
If the file is located on the same host that served the page containing the javascript you could try sending an ajax request and verify the returned status code:
function checkFile(fileUrl) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('HEAD', fileUrl, true);
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
if (self.xmlHttpReq.status == 200) {
alert('the file exists');
} else if (self.xmlHttpReq.status == 404) {
alert('the file does not exist');
}
}
}
self.xmlHttpReq.send();
}
checkFile('/somefile.xml');
Javascript doesn't really have any file handling functions. Your best bet is to do the check server side and send some context back to the client.
If you want to get super hacky you COULD call an xmlHttpRequest (If you're using jQuery take a look at the $.ajax function)
Once you call $.ajax you can use the success/error handlers to determine what to do. It should spit out an error if the file doesn't exist.
This of course is NOT a recommended way to do this.
I don't have enough reputation to post comments so let me note that in the Anwar Chandra's answer (non-jQuery version) you have to call eventually:
myrequest.send();
Also, the HEAD method would be better to "check existence of a file", because you don't need to read the whole file from the server.