In this discussion and in chat I understood that a callback is the only way to go!
"
Get from the server a link with ajax, write the link in a variable, open an xml with this link, doing some stuff with the xml: is callback the only way?
"
I'm trying to understand what a callback is. I read some blog, but I still have problems.
What I have now in JS is
1) a function to open an xml.
2) function to request the link of the xml in first function
Can someone provide an example in PLAIN JAVASCRIPT of how to nest these two functions?
The server generate the link of the xml because I'm making a multi user web site and every user has it's own xml. So I need to ask the server what is the link of the xml and then open it. Is there an easy way to achieve this? I need plain javascript no jquery.
Thanks!
In general, a "callback" is a function which will be executed at a later time when an asynchronous process is completed.
So you might start by defining the function that should happen when the data is retrieved from the server (the "second" function, intuitively, but you should define it first because it's the business functionality you're looking to achieve and not just an implementation concern). Something as simple as:
var doSomethingWithTheData = function () {
// do, well, something with the data
};
This assumes that you have the data, which you don't yet. But the AJAX call will get that data. You can now use this function as your callback for the AJAX call. Taking the AJAX example from MDN, you might have this:
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.onreadystatechange = doSomethingWithTheData;
// perform the AJAX request
The httpRequest object will contain the response from the server after the AJAX call is executed and completed. (Remember that this happens asynchronously, so it won't contain the response on the immediate next line of code. It will at some later time which you don't control. Hence the need for the callback.)
I recommend walking through that full MDN article to get all the details, particularly on handling errors and such. But the data you're looking for (assuming nothing went wrong) would be in httpRequest.ResponseText. So, also assuming your variables are scoped to allow this (you can modify that as needed):
var doSomethingWithTheData = function () {
var data = httpRequest.ResponseText;
// do, well, something with the data
};
Excuse me, #David
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari,
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://myserver.mydomain/getMyUsersXMLUrl?user=pete";
httpRequest.open("GET", url, true); // next ajax to retrieve XML - File
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState == 4) { // response received
var response = httpRequest.responseText; // this should contain you url
httpRequest.open("GET", response, true); // next ajax to retrieve XML - File
// and the same as for the first request
}
}
If You just need to download a xml you dont need a callback . Just take a look at jquery and ajax. Retrieving a callback from a server is not possible . JSONP does deal with callbacks that are called by the server (actually they arent ) Butter you wont need it. I think you are messaging the xhttprequestobject
A callback function is simply a piece of executable code passed as a parameter to another piece of code. For example:
function first (arr, predicate) {
// no predicate supplied, return first element
if (!predicate) return arr[0];
for (var i = 0; i < arr.length; i++) {
// return first element satisfying predicate
if (predicate(arr[i])) return arr[i];
}
// no element satisfying predicate, return null
return null;
}
// second parameter is an anonymous function
// will alert 4, as it's the first element which will return true
alert(first([1, 2, 3, 4, 5, 6], function(n) { return n > 3; }));
Callbacks are useful for asynchronous tasks, or for library functions which need extra customization at runtime.
Related
I'm currently writing a search function using JavaScript.
However, when I attempt to test my creation, I find that it stops about halfway through for no discernible reason.
Below is my code:
document.getElementById("test").innerHTML = "";
var Connect = new XMLHttpRequest();
Connect.open("GET", "xmlTest.xml", false);
document.getElementById("test").innerHTML = "1";
Connect.send(null);
document.getElementById("test").innerHTML = "2";
var docX = Connect.responseXML;
var linjer = docX.getElementsByTagName("linjer");
The first line is there to clear a potential error message from earlier in the code. Then I attempt to open up an XML file, as I need to read from it.
As you can see, I've entered two debug statements there; they will print 1 or 2 depending on how far I get in the code.
Using this, I've found that it stops exactly on the Connect.send(null); statement (as 1 gets printed, but 2 never does), but I can't figure out why. Google says that it might be that chrome can't access local files, but when I found a way to allow Chrome to do this, it still did not work.
What am I doing wrong?
This might be a synchronous issue that requires a response that your code simply is not getting.
Try using an async call instead:
Connect.open("GET", "xmlTest.xml", true);
Also make sure to setup proper callbacks since you'll be using async here now instead of synchronous code, like so:
// Global variable scope
var docX;
var linjer;
// Define your get function
getDoc = function(url, cbFunc) {
var Connect = new XMLHttpRequest();
// Perform actions after request is sent
// You'll insert your callback here
Connect.onreadystatechange = function() {
// 4 means request finished and response is ready
if ( Connect.readyState == 4 ) {
// Here is where you do the callback
cbFunc(Connect.responseXML);
}
};
// 'true' param means async, it is also the default
Connect.open('GET', url, true);
Connect.send();
}
// Define your callback function
callbackFunction = function(responseXML) {
// XML file can now be stored in the global variable
window.docX = responseXML;
window.linjer = window.docX.getElementsByTagName("linjer");
}
// And here is the call you make to do this
getDoc("xmlTest.xml", callbackFunction);
For better understanding of all of this, do some research on scope, closures, callbacks, and async.
i cant find an answer to this
i have been learning ajax lately but i learned how to do it all in javascript
now i go swiming around ajax question here and almost all are using jquery
so i end up confused. should i use normal javascript or do it through jquery?
so what are the differences?
this is my normal approach
var xmlHttp = createXmlHttpRequestObject(); //you first create the object to this function global
function createXmlHttpRequestObject() //here you instruct the function
{
var xmlHttp; //here you tell it to use the local variable not the global version of it because this returns to the global with the propper values
if (window.XMLHttpRequest) //if the "window" or browser is aware of this Object 90% of browsers
{
xmlHttp = new XMLHttpRequest(); // if true then the variable is now equal to the heart of ajax
}
else //for internet explorer
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp; //we return it back to daddy the global variable this objects does everything
//this object is everything in ajax for the most part
}
function process() //function that gets called on load of the body
{
if(xmlHttp) //if its not void or if you can run ajax
{
try //try catch statement are sort of required for the heart of things like ajax and server communication
{
xmlHttp.open("GET", "bacon.txt", true); //here 1st type of call 2nd from where 3rd
//is it true assyscronly or at the same time
//it does not start the connection to the server, its only sets up settings for the connection
xmlHttp.onreadystatechange = handleServerResponse; //anytime something changes[propertie]
//i want to call that function handleserverresponse
//begin communication
xmlHttp.send(null); //this is what communicates to the server makesure on ready statechane before this
//if the server responds you want to make sure everything is taking care of like what function onready state change is it going to call
//or what to do like open a text file in this case
} catch(e)
{
alert( e.toString() ); //alert the error message as a string on a popup
}
}
}
//handling the server response
function handleServerResponse()
{
theD = document.getElementById('theD'); //get the div in a var
if(xmlHttp.readyState==1) //if the connection to the server is established
{ //google crhome may not show this one, some browsers ignore some states
theD.innerHTML += "Status 1: server connection established<br>";
}
else if(xmlHttp.readyState==2) //request received, hey client i am the server and i received your request
{
theD.innerHTML += "Status 2: request reveived <br>";
}
else if(xmlHttp.readyState==3) //while is doing its thing
{
theD.innerHTML += "Status 3: processing request <br>";
}
else if(xmlHttp.readyState==4) //your request is finished and ready
{ //it means your response is ready but doesnt guaranteed no trouble
if(xmlHttp.status==200) //if the status is 200 then is succesufll
{
//IF everthing finally good THE GOOD PART
try //put all your calls on a try statement REMEMBER
{
//get the txt file as a string
text = xmlHttp.responseText; //response text n a normal string
theD.innerHTML += "Status 4: request is finished and response is finished";
theD.innerHTML += text;
}catch (e)
{
alert( e.toString() );
}
} else //for the other statuses like 404 else somehting went wrong
{
alert( xmlHttp.statusText ); //this will give you a status report on the wrong
}
}
}
jQuery simply wraps all of the XmlHttpRequest calls into a simple to use library. In the guts of jQuery you will see code that creates the XmlHttpRequest objects.
You can see the code that does this here:
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js
The nice thing about using a framework like jQuery is that they handle a lot of the browser idiosyncrasies for you. They also handle a lot of the edge cases you might not think about when writing your code.
Using jQuery is just for ease of use. If you prefer doing it the javascript way then carry on doing that.
jQuery ajax calls do exactly the same as what you are doing but jQuery is a javascript framework which simplifies what you write.
jQuery is a javascript framework which contains library of simplified functions compared to the Native Javascript. One of the functions is the XMLHttpRequest.
This way we just need to implement functions that is needed to implement without needed to write the traditional codes to setup the AJAX system to work
You may learn more about jQuery ajax here:
http://api.jquery.com/jQuery.ajax/
I am using a second party file downloader which returns a progress event. I can capture the event and call a program on the server to perform an update (for security purposes so I can tell the most recent activity).
I get about 30 events per second all at percent downloaded 1%, then 30 more at 2%, then 30 more at 3%, etc. I would like to limit my http calls to only once per percentage change, 1%, 2%, 3%, etc. I would put a hidden field on the page and compare that and update it, but I cannot refresh the page since the download is in progress.
Is there a way to use some type of client side storage within javascript or jquery for this?
In other words, I need to be able to tell when the PercentCurrent value changes from 1 to 2, etc.
My javascript function looks like this:
function onProgress(PercentTotal, PercentCurrent, Index){
var xmlhttp;
//The handler will update the file progress
if (typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}
if (!xmlhttp) {
throw "Browser doesn't support XMLHttpRequest.";
}
var data = "";
xmlhttp.open("POST", "UpdateProgress.aspx?PercentCurrent=" + PercentCurrent, true);
//Send the proper header information along with the request
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//xmlhttp.setRequestHeader("Content-length", data.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(data);
}
Thank you,
Jim
JavaScript does indeed have variables, you just need to store one in a scope that's accessible to your onProgress code. You may just be able to use a var in the same place onProgress is declared, but a simple and JavaScripty way to make that variable "private" is to use a closure:
var onProgress = (function(){
var lastSend = 0;
return function(PercentTotal, PercentCurrent, Index){
if (Math.floor(PercentCurrent) > lastSend) {
lastSend = PercentCurrent;
var xmlhttp…
}
}
})();
This'll look a little confusing if you haven't worked with JavaScript much. Here's what's going on:
I create a variable called onProgress
I create and immediately run an anonymous (unnamed) function, like this: (function(){ … })()
This function defines a local variable, lastSend, and returns the real onProgress function.
Whenever a function is called in JavaScript, it has access to the scope in which it was created. So, whenever onProgress() is called, it'll have access to the lastSend variable, and can check that progress is has moved past the next whole percent.
Of course, this is a bit ugly, and it can only be used once on a page (since there's only one closure with one lastSend variable. Instead of assigning it to a name, you might pass it directly into the function which calls it, anonymously (see below). Then, a new copy of the function, with a new closure, gets created when you hit downloadFile.
Your original question is tagged jquery. If you are indeed using jQuery on the page, you can simplify the posting of data significantly (down to one line) and make it more compatible, with jQuery.post:
$.post("UpdateProgress.aspx", { PercentCurrent: PercentCurrent });
(This would replace all the XMLHTTPRequest-related code in onProgress.)
So, using a closure and jQuery.post might look like this:
// Not sure what your second-party file downloader looks like
fileDownloader.downloadFile((function(){
var lastSend = 0;
return function(PercentTotal, PercentCurrent, Index){
if (Math.floor(PercentCurrent) > lastSend) {
lastSend = PercentCurrent;
$.post("UpdateProgress.aspx", { PercentCurrent: PercentCurrent });
}
}
})());
Have a look at jQuery's .data(). It allows you to store data and attach it to a particular DOM element like so:
$('body').data('foo', 52);
$('body').data('foo'); // 52
I am not sure to understand your problem. Is the page continously reloaded? If it is not all that you need to do is:
var lastPercent = null; // you need to initialize this when it all starts again.
function onProgress(PercentTotal, PercentCurrent, Index){
var xmlhttp;
if (lastPercent == PercentCurrent)
return; //Does nothing if no change occurred.
lastPercent = PercentCurrent;
//The handler will update the file progress
if (typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}
if (!xmlhttp) {
throw "Browser doesn't support XMLHttpRequest.";
}
var data = "";
xmlhttp.open("POST", "UpdateProgress.aspx?PercentCurrent=" + PercentCurrent, true);
//Send the proper header information along with the request
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//xmlhttp.setRequestHeader("Content-length", data.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(data);
}
I have to request data for a JS-script from a MySQL database (based upon a user-id).
I did not find a simple solution for JavaScript and it was not possible to load the data using ajax, because the database is available under a different domain.
I implemented a workaround using PHP and curl.
Now the JS has to "wait" for the request to finish, but the script is of course running asynchronously and does not wait for the response.
I know that it's not really possible to wait in JS, but it must be possible to return value like this.
I also tried using a return as another callback, but that didn't work of course, because the getter-function will run further anyway.
How can I implement a simple getter, which "waits" and returns the response from the HTTP-request?
Thanks for any other clues. I'm really lost at the moment.
This is a excerpt from the source code:
/**
* Simple getter which requests external data
*/
function simple_getter() {
// http request using a php script, because ajax won't work crossdomain
// this request takes some time. function finished before request is done.
/* Example */
var url = "http://example-url.com/get_data.php?uid=1234";
var response_callback = handle_result_response;
var value = send_request( url, response_callback );
value = value.split('*')[0];
if (value === '' || value == const_pref_none) {
return false;
}
/* 1. returns undefinied, because value is not yet set.
2. this as a callback makes no sense, because this function
will run asynchronous anyway. */
return value;
}
Additional information about the used functions:
/**
* Callback for the send_request function.
* basically returns only the responseText (string)
*/
function handle_result_response(req) {
// do something more, but basically:
return req.responseText;
}
/**
* Requests data from a database (different domain) via a PHP script
*/
function send_request( url, response_callback ) {
var req = createXMLHTTPObject();
if (!req)
return;
var method = (postData) ? "POST" : "GET";
req.open(method, url, true);
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
// More not relevant source code
// ...
req.onreadystatechange = function () {
// More not relevant source code
// ...
response_callback(req);
}
if (req.readyState == 4)
return;
req.send(postData);
}
Not really relevant code, but required for the HTTP-request:
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0; i<XMLHttpFactories.length; i++) {
try {
xmlhttp = XMLHttpFactories[i]();
} catch (e) {
continue;
}
break;
}
return xmlhttp;
}
You really, really shouldn't try to synchronously wait for a network request to complete. The request may never complete, may hang and take a long time, and so on. Since JavaScript is single threaded, and in fact all major browser engines are single threaded, this will cause your entire page to hang while waiting for the request, and in some browsers, may cause the entire browser to hang.
What you should do is replace code like this:
var returned = some_request('http://example.com/query');
do_something_with(returned);
with code like this:
some_request('http://example.com/query', function (returned) {
do_something_with(returned);
});
That way, you will never cause your page or the browser to hang waiting for the request, and can simply do the work once the response comes in.
I don't see whats wrong with your code in general.
When you make a request, provide a Callback. When a response comes back, which you can easily detect, execute the Callback and pass it the result.
This is the way client side apps work.It is not procedural, but works by events.
You present the screen to the user and wait
The user makes an action
You call the server, set a callback and wait
The response come and you execute the callback and wait for another step 2
Rather than trying to change that, you need to fit with that or it will be a painful experience.
Javascript is not multithreaded. It means a single statement is run at a time. The real asynchronism come from the time the server takes to respond and call the callback. You never know which call will come first and need to build your program with that in mind.
I'm using AHAH (as outlined here http://microformats.org/wiki/rest/ahah) to make two calls to populate HTML on a page. The calls happen after the document is ready and are fired off one after another. The result, every time, is the first call gets overwritten with the last calls response. So I'll have two of the same chunks of HTML on the page instead of two unique pieces of code. Sometimes the first call doesn't even get to evaluate it's call back and thus remains empty.
Any ideas?
If you're using the exact code on that page, it's not surprising, as the example there uses a single global variable to store the XMLHttpRequest being made. So there's no way it can work for more than one simultaneous request: calling the function a second time overwrites the req with a new one, causing the req read by ahahDone to be the wrong request.
If you want to allow this you'll have to make req a local variable (by declaring it var in function ahah()), and pass it with the target to the ahahDone() function. Or just do it inline:
function Element_loadHTML(element, url) {
var req= null;
if (window.XMLHttpRequest) {
req= new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
req= new ActiveXObject('MSXML2.XMLHttpRequest');
} catch() {}
}
if (!req) {
element.innerHTML= 'Browser does not support XMLHttpRequest';
return;
}
element.innerHTML= 'Loading...';
req.onreadystatechange= function() {
if (req.readyState===4)
element.innerHTML= req.status===200? req.responseText : 'Error '+req.status;
};
req.open('GET', url);
req.send(null);
}
Element_loadHTML(document.getElementById('appdata'), 'appdata.part.html');
Element_loadHTML(document.getElementById('foo'), 'bar.part.html');
The stuff with the browser sniffing and trying to execute script tags is hopeless and broken; don't use it. It's not good practice to be loading <script> element content into the page.