In a chrome extension I am writing I need to validate some objects I have stored in localStorage against my server . For this I created a for loop that simply sends the data for each localstorage element and that needs to do something with the response . The code is something like this:
for (var key in localStorage) {
if (! some condition )
continue;
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4 && httpRequest.response == 200) {
do something with 'key' from the for loop
}
}
};
var url = BASE_PATH ;
httpRequest.open("POST", url);
httpRequest.send(some data);
}
However while debugging it seems that in the ajax response , the 'key' from the for loop isn't the key I need : I was expecting to get the same key from the for loop that matches each ajax call , what I got was the same key for all ajax calls .
Am I doing something wrong or expecting something that isn't possible ? I thought that since the ajax is inside a closure function , the values are kept in memory or something of the sort .
Extract the actual Ajax call to a separate function:
function AjaxCall( key ) {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if ((httpRequest.readyState === 4) && (httpRequest.response == 200)) {
do something with 'key' from the for loop
}
};
var url = BASE_PATH ;
httpRequest.open("POST", url);
httpRequest.send(some data);
}
for (var key in localStorage) {
if ( some condition ) {
AjaxCall( key );
}
}
Reason is, that you are creating a closure with the function passed to onreadystatechange. All those functions point to the same key variable, which holds just one (the last) value for all Ajax calls, after the loop is finished.
When you create a separate function (like the AjaxCall() in my example), you create a different context for each call and hence all callbacks point to different keys.
Related
I'm building a user signup for a web site. It uses AJAX to send data. I have created an object to store user data and send the object to the server via function.
sendUserData(passenger, "user_registration.php");
Note :
signupUser(); is called with a button click in HTML document.
sendUserData() is the function for sending the user details.
passenger is the object which stores the user data.
sendUserData(); is in a separate Script linked to the HTML page.(Global Scope)
This is the code I used to do this
//Sign Up A User
var signupUser = function () {
// User Object
var passenger = {
userName : document.getElementById("userFirstName").value,
userEmail : document.getElementById("userEmail").value,
country : document.getElementById("country").value,
password : document.getElementById("userPassword").value,
passwordVerify : document.getElementById("userPasswordVerify").value,
passwordStatus : Boolean
};
// Verifies the password ("password" and "re-enter password")
verifyPassword(passenger.password,passenger.passwordVerify,passenger.passwordStatus);
if (passenger.passwordStatus == true) {
sendUserData(passenger, "user_registration.php");
console.log(passenger);
}
};
The problem is with invoking the function signupUser() on the button,
the function stops after verifyPassword(); .
sendUserData(passenger, "user_registration.php"); invoked in the chrome debugging tool, it gives an error "passenger is not defined at : 1:13"
Please help me to find an answer.
Thank you.
Edit:
sendUserData(); function
This is in a separate javascript file linked to the HTML page.
function sendUserData (userDetails, destinationPage, functionToExecute) {
var userDetailsJson = JSON.stringify(userDetails);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if(xhr.readyState == 4 && xhr.status == 200 ) {
console.log(userDetailsJson);
window.alert("Successfully Posted");
console.log(xhr.responseText);
if(functionToExecute) {
functionToExecute();
}
}
};
xhr.open("POST", destinationPage, false);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("m=" +userDetailsJson);
}
So this hinges on passenger.passwordStatus == true not working out.
You initialised it as passwordStatus: Boolean which already doesn't do what you think it does.
Then you pass the parameter to the verifyPassword function, which presumably looks something like:
function verifyPassword( password, retype, status) {
// verify...
status = true;
}
This reassigns status and does not affect passenger.passwordStatus in the outer scope at all.
Therefore, when it comes time to check the status, you're still comparing Boolean == true, which is never going to work.
You probably want something more like:
if( verifyPassword( passenger.password, passenger.passwordVerify)) {
sendUserData(...);
}
Have verifyPassword do either return true; or return false; as required.
And get rid of this passenger.passwordStatus thing entirely.
function saveToDataBase(save_id,textarea_id,question_no,assg_name,testinput,testoutput)
{
document.getElementById(save_id).addEventListener('click',function(){
//alert("Hello");
var question=document.getElementById(textarea_id).value;
var question_id=assignment_name+question_no;
var request;
var url="saveQuesToDataBase.jsp?question="+question+"&question_id="+question_id+"&assg_name="+assg_name;
for(var i=0;i<testinput.length;i++)
{
var v=document.getElementById(testinput[i]).value;
url=url+"&testinput"+i+"="+v;
}
for(var i=0;i<testoutput.length;i++)
{
var v=document.getElementById(testoutput[i]).value;
url=url+"&testoutput"+i+"="+v;
}
var len=testinput.length;
url=url+"&size_of_arr="+len;
if(window.XMLHttpRequest)
{
request=new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
request=new ActiveXObject("Microsoft.XMLHTTP");
}
try
{
request.onreadystatechange=function()
{
if(request.readyState==4 && request.status == 200)
{
alert(request.responseText);
}
};
request.open("GET",url,true);
request.send();
}
catch(e){alert("Unable to connect to server");
}
})
}
The function is called on click, but not redirected to saveQuesToDataBase.jsp . Please see if I could append things to url this way ? Tell me the better way.
testinput and testoutput are the two arrays of id's of textareas.
I used loop to retrieve id and to get the value.
For your code design,I have two suggestions:
a. First I would recommend you using jQuery ajax instead of original Ajax,it will hide the implement of different browsers.With it you can make it like below:
$.ajax({
url:your_request_url,
type:"post",//or get
data:your data,
success:function(data){},
error:function(){}
});
b. since Http Get method has parameter length limit,details can be found at maximum length of HTTP GET request?. You need to use POST instead of GET,while using POST,when can using data to pass more parameters to ajax:
var params ={};//define a parameter object
for(var i=0;i<testoutput.length;i++)
{
var v=document.getElementById(testoutput[i]).value;
params["testoutput"+i]=v;
}
$.ajax({
url:your_request_url,
type:"post",//or get
data:params,//passing the parameters.
success:function(data){},
error:function(){}
});
Hi I've been trying to clarify this but there's something I'm still confused about. I know that you can't return values from asynchronous functions so I've referenced this answer's top answer Returning value from asynchronous JavaScript method?
What I'm trying to do is use the flickrAPI to get the biggest size image. The flickrAPI allows one to search images, so I use this to get the photo_id, then I use this photo_id to procses another request to the API's getSize method to get the URL for the biggest size photo.
The code looks a little messy as it is, because I have a method called flickrRequest which sends an XMLHttp request and gets back a JSON string. I know that I can achieve what I want by writing the functions as follows:
function flickRQforimage() {
...got ID
function flickrRQforSize() {
...got maxsizeURL
create image based on maxsizeURL here
}
}
but I was wondering if it was possible to do something like this
function flickRQforimage() {
...got ID
function flickrRQforSize() {
...got maxsizeURL
}
create image based on maxsizeURL here
}
or even create image based on maxsizeURL here
In general my question is whether it is possible to have a callback function that references another statically defined function (I think?). The specifics of the my function is that it takes a callback and the ID and URL processing happens in those callbacks:
flickrRQ(options, cb)
I am wondering whether/what would happen if that unnamed function is instead something else, say flickrRQ(options, processPhoto(data)), and then I define the function in a separate method. This just makes sense for me because I want to keep functionality for the URL processing separate in an attempt to make my code cleaner and more readable.
I tried the following below and it didn't work. Nothing prints. I even have a console.log in the processPhoto method. In fact anything inside of the flickrRQforSize method seems to not evaluate
flickrRQforSize(options, function(data) {
processPhoto(data)
}
even though in the flickrRQforSize definition, a callback function is taken as an argument. I'm suspecting there must be something about functions/async calls that I don't understand.
I hope this is clear -- if not, I can post my actual code.
Here's my code:
var flickrRequest = function(options, xhrRQ, cb) {
var url, xhr, item, first;
url = "https://api.flickr.com/services/rest/";
first = true;
for (item in options) {
if (options.hasOwnProperty(item)) {
url += (first ? "?" : "&") + item + "=" + options[item];
//parses to search equest;
first = false;
}
}
//XMLHttpRQ to flickr
if(xhrRQ == 1 ) {
xhr = new XMLHttpRequest();
xhr.onload = function() { cb(this.response); };
xhr.open('get', url, true);
xhr.send();
};
}
var processPhotoSize = function(photoJSON) {
var parsedJSON = JSON.parse(data);
var last = parsedJSON.sizes.size.length;
console.log(parsedJSON.sizes.size[last-1].source);
return parsedJSON.sizes.size[last-1].source;
}
...
flickrRequest(options, 1, function(data) {
...
flickrRequest(sizesOptions, 0, function(data) {
parsedJSON = JSON.parse(data);
console.log(parsedJSON);
processPhotoSize(data);
});
}
I have a JavaScript function that is being called. I need to have it call a PHP function and return a true/false.
The script with the function is in the file /db/cancel_hike.php
My current JS looks like this:
function uncancelHike( hike_id )
{
//var url = "/db/cancel_hike.php;
var success = null;
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.open("GET", url , true);
request.onreadystatechange = function()
{
if (request.readyState == 4)
{
var xmlDoc = request.responseXML;
// obtain the array of markers and loop through it
markers = xmlDoc.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++)
{
// obtain the attribues of each marker
success = markers[i].getAttribute("success");
if ( success == "true" )
{
document.getElementById("success").style.display = 'block';
document.getElementById("warning").style.display = 'none';
document.getElementById("error").style.display = 'error';
}
if ( success == "false" )
{
document.getElementById("success").style.display = 'none';
document.getElementById("warning").style.display = 'none';
document.getElementById("error").style.display = 'block';
}
}
}
}
request.send(null);
return false;
}
What I am having trouble with is:
How to call an actual function in the PHP script?
Do I absolutely need to have some XML returned? Or is there a way to just get back the returned value?
I am using YUI JS library. Do I need to make some calls to it, or is it not necessary in this case?
How to call an actual function in the PHP script?
You can't. You request URIs.
Write a PHP script that calls the function you want and place it at the URI you call.
(You can use query strings and the like as the input to an if statement that you use to conditionally call different functions)
Do I absolutely need to have some XML returned? Or is there a way to just get back the returned value?
You can return any kind of data you like.
I am using YUI JS library. Do I need to make some calls to it, or is it not necessary in this case?
It's a library. You never need to make calls to it. It often simplifies the code you have to write.
How to call an actual function in the PHP script?
Do I absolutely need to have some XML returned? Or is there a way to just get back the returned value?
Well, you don't call the actual function. What you want to do is pass variables using GET, that is, by appending them to the URL like file_name.php?var1=this&var2=that to pass var1 of "this" and var2 equaling "that." You retrieve them in the PHP file with $_GET['this'] and $_GET['that']. Whatever PHP outputs to the page via echo, print_r, etc. is then sent back in a request object as part of its responseText property.
You just set url in request.open to a URL on your site. For example, in your .js file:
request.open("GET", "answer_me.php?hike_id=" + hike_id, true);
And in your .php file:
<?php
$hike_id = $_GET['hike_id'];
if ($hike_id < 5) {
echo "true"; // echo true would return "1", BTW
} else {
echo "false"; // echo false would return nothing
}
Note that that will just return a string value to request.responseText of false, thus you could do this:
var result = request.responseText;
if (result === "true") {
...
document.getElementById("success").style.display = "block";
...
} else {
...
document.getElementById("success").style.display = "none";
...
}
You do not need it to be XML, especially as it looks like you're not really using the loop (the same three DOM elements are being assigned values each time).
And honestly, for AJAX I'd recommend using a framework like jQuery (or YUI, although I don't find its AJAX stuff as intuitive). Your entire code would look like this:
var $success = $("#success");
var $error = $("#error");
function cancelHikeCallback(data) {
var is_success = (data === "true");
$success.toggle(is_success);
$error.toggle(!is_success);
}
function cancelHike(hikeIdToSend) {
$.get("/db/cancel_hike.php", {hike_id: hikeIdToSend}, cancelHikeCallback);
}
IMO things like jQuery's $.ajax ($.get is a specialized form of $.ajax) make this stuff much easier to read and debug.
jsFiddle Example
function addphoto()
{
var ajaxRequest = initAjax();
if (ajaxRequest == false)
{
return false;
}
// Return Ajax result when the state changes later
ajaxRequest.onreadystatechange = function()
{
if(ajaxRequest.readyState == 4)
{
alert(ajaxRequest.responseText);
return ajaxRequest.responseText;
}
}
// Capture form elements
var values = {
"category" : encodeURIComponent(document.addphoto.category.options[document.addphoto.category.selectedIndex].value),
"photo_title" : encodeURIComponent(document.addphoto.photo_title.value),
"photo_descrip" : encodeURIComponent(document.addphoto.photo_descrip.value)
}
var queryString = '?', i = 0;
for (var key in values)
{
if (i != 0)
{
queryString += '&'
}
queryString += key + '=' + values[key];
i++;
}
// Execute Ajax
ajaxRequest.open("POST", "ajaxcheckform.php" + queryString, true);
ajaxRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ajaxRequest.setRequestHeader("Content-length", queryString.length);
ajaxRequest.setRequestHeader("Connection", "close");
ajaxRequest.send(null);
}
function ajaxCheckform(formname)
{
var response = addphoto(); // <--This is undefined and not sure why
var responseObj = JSON.parse(response);
if (responseObj.success == 1)
{
// Successful form!
alert(responseObj.success_text);
}
else
{
// Error!
alert(responseObj.error);
}
}
I'm sure I must be making some basic error somewhere, but I'm having trouble locating it. In this script, ajaxCheckform() is a function that executes one of several similar functions. Above, I included addphoto(), which is one of several functions I'll need that look like this.
On a side note, I'd love to know I can call upon a function dynamically. The addphoto() function will be only one such function being called up at that moment and I'm trying to find a way to pass formname as the function I need. I've searched Stackoverflow and Google. I've found nothing that works.
Note, I'm aware of jQuery, but I'm not there yet. I need this function to work first.
It is not addphoto() thats undefined but response is undefined. ajaxRequest is asynchronous and the addphoto() function will return before the request completes.
try this
function addphoto() {...
// Return Ajax result when the state changes later
ajaxRequest.onreadystatechange = function()
{
if(ajaxRequest.readyState == 4)
{
alert(ajaxRequest.responseText);
var responseObj = JSON.parse(ajaxRequest.responseText);
if (responseObj.success == 1) {
// Successful form!
alert(responseObj.success_text);
}
else {
// Error!
alert(responseObj.error);
}
}
}
....
}
function ajaxCheckform(formname) {
addphoto();
}
That's because response is set to the return of addphoto(), which is nothing. What you want to do is have ajaxCheckForm get called when the AJAX call is completed:
// Return Ajax result when the state changes later
ajaxRequest.onreadystatechange = function()
{
if(ajaxRequest.readyState == 4)
{
ajaxCheckform(ajaxRequest.responseText);
}
}
Then your ajaxCheckform will work with that data:
function ajaxCheckform(responseText)
{
var responseObj = JSON.parse(responseText);
if (responseObj.success == 1)
{
// Successful form!
alert(responseObj.success_text);
}
else
{
// Error!
alert(responseObj.error);
}
}
You can't return from an event handler (which onreadystatechange is).
You have to do the work inside that event handler.
addphoto() does not return anything (or rather, returns inconsistently) ... the onreadystatechange event's handler is returning the value, but there is no caller that will receive that json string.
I'd highly suggest that you abstract these details away with something like jquery ... just follow the docs for suggested usage and this code will be much simpler
You're sending a GET style parameter list to a POST method.
You need to send that string in the body of your HTTP request.
var response = addphoto(); // <--This is undefined and not sure why
The addphoto() function never has a return statement in it, so it returns undefined. And the ajaxRequest is asynchrous and wont return immediately.