Modify global variable from ajax request - javascript

I know this has been asked countless times, but i can't figure out the problem. As far as i know, you can modify global variables inside functions in javascript. It doesn't work for me.
var lastMessage = 0;
function loadChat() {
$.post("/lastmessage", { roomid: roomId })
.done(function(data) {
var response = JSON.parse(data);
if (response.state == "success") {
lastMessage = response.message;
console.log("Inside: " + lastMessage);
}
});
}
console.log("Outside: " + lastMessage);
This gives me
Outside: 0
Inside: 17
The inside value is correct, the outside is not. What could the problem possibly be?

It's asynchronous, therefore when you call it from outside, it has not finished executing yet. What this means is that this part of your code is only reached once the post has completed
.done(function(data) {
var response = JSON.parse(data);
if (response.state == "success") {
lastMessage = response.message;
console.log("Inside: " + lastMessage);
}
});
but console.log("Outside: " + lastMessage); will continue executing without waiting, since post is asynchronous.
If you want something to happen after you retrieve the value you, one option would be to use a callback function, such as:
function printMessage(message) {
console.log(message)
}
function loadChat(callback) {
$.post("/lastmessage", { roomid: roomId })
.done(function(data) {
var response = JSON.parse(data);
if (response.state == "success") {
lastMessage = response.message;
callback(lastMessage);
}
});
}
loadChat(printMessage);

Related

While looping a jquery ajax call

I want to control the number of ajax calls to a controller using a while loop.
var counter = 0;
$('#filter-form').submit(function (event) {
event.preventDefault();
alert("counter init = " + counter)
while (counter < 10) {
(function () {
$.ajax({
url: '/algorithm',
method: 'GET',
data: $('#filter-form').serialize() + "&counter=" + counter,
success: function (data) {
alert("The data is " + data);
setCounter(parseInt(data))
},
error: function (xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
}
});
})();
}
alert("counter end = " + counter)
});
function setCounter(data) {
counter = data
}
Controller:
#RequestMapping(value = "/algorithm")
#ResponseBody
public String test(#RequestParam Map<String, String> allRequestParam) {
int counter = Integer.parseInt(allRequestParam.get("counter"));
counter++;
return Integer.toString(counter);
}
The controller basically just increments the counter and returns it and in the ajax success: it will set the global counter to that number.
When I do this, the page just freezes and I cannot click anything. I put the ajax call in a function for scoping but it still does not work. When I use a for loop, it seems the ajax does not invoke because I do not get any success or error alerts.
It doesn't work for a simple reason: the $.ajax call is asynchronous.
Take this example:
$(function() {
var t = 1;
console.log("Hey, the ajax will start! t's value: " + t);
$.ajax({
url: 'www.google.com.br',
method: 'GET',
success: function (data) {
t++;
console.log("We've received an answer! t's (incremented) value: " + t);
},
error: function (xhr, status, error) {
t++;
console.log("We've received an error! t's (incremented) value: " + t);
}
});
console.log("Hey, the ajax just ended.... Not really. t's value: " + t);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The output is:
Hey, the ajax will start! t's value: 1
Hey, the ajax just ended.... Not really. t's value: 1
We've received an error! t's (incremented) value: 2
That's because the $.ajax call is nonblocking, thus is doesn't block the program until it is finished, allowing the program to keep on executing the next line of code and continue running the ajax task in the background.
It is a recurrent issue in SO, so instead of providing solutions again here I'll ask you to read more on the questions:
How do I return the response from an asynchronous call?
How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?
What does Asynchronous means in Ajax?
while will block synchronously until its condition is reached. Even if responses come back, the response will be asynchronous; the current thread (the while loop) will keep blocking forever.
Don't block. I don't see any reason to use a loop in the first place - instead, simply test to see if the counter is greater than the allowed number, and if it is, return:
$('#filter-form').submit(function (event) {
event.preventDefault();
alert("counter init = " + counter)
if (counter >= 10) return;
If you wanted to make multiple requests in parallel on form submit, you could do that, but you would have to keep track of the counter client-side:
var counter = 0;
$('#filter-form').submit(function (event) {
event.preventDefault();
alert("counter init = " + counter)
while (counter < 10) {
counter++;
// ... make request
As others have said your problem is that the call is asynchronous. This simple example may give you some idea about how to control the flow. It should be simple enough to apply it to your case.
I am simulating what you need to make your code work. For the errors, I am passing back null but you should bubble up any errors that may occur and either halt execution or deal with them some other way.
var count = 0; // used to store your count
// This represents the function you are
// waiting on with your ajax calls
function waitOne(num, callback) {
setTimeout(() => {
callback(null, num);
}, 1000);
}
// This represents your ajax call
function callWaitOne(callback) {
waitOne(count, (err, num) => {
// Your result is here
console.log(num);
// Callback to let the control function
// know the ajax has returned
callback(null);
});
}
// This will control the calls
function printWaitOne() {
callWaitOne((err) => {
if (count < 10) {
count++;
// Only calls if its callback
// has been called.
printWaitOne();
}
});
}
printWaitOne();

How can I control functions to execute in order?

I am newbie in Javascript. I am trying to manage couple of function in order. But when it gets to API calls it dosen't wait for response and go backs to continue its execution and makes my code messy. This is a sample:
function readFacebook()
{
var myID = getMyID();
console.log("myID= " + myID);
}
function getMyID(){
FB.api('/me', function(response) {
console.log("response.id= "+response.id);
return(response.id);
});
}
The output is completely strange. First
console.log("myID= " + myID);
show output and then
console.log("response.id= "+response.id);
will be called. Anyone can explain how I can force it to implement in order. I meant program should wait until response from facebook instead of working asynchronously!
EDIT
I actually call 3 time API from main function to three sub functions. How can I organise this:
function getMyID(){
FB.api('/me', function(response) {
console.log("response.id= "+response.id);
return(response.id);
});
}
function readFacebookEvent(id)
{
var myID = getMyID();
console.log("myID= " + myID);
FB.api('/me/events', function(response) {
for(i=0; i<response.data.length;i++) {
var str;
var eventID = response.data[i].id;
getEvent(eventID,myID);
}
});
}
function getEvent(eventID,myID){
FB.api("/"+ eventID , function (response3) {
if (response3 && !response3.error) {
//console.log(response3);
var date = new Date((response3.start_time || "").replace(/-/g,"/").replace(/[TZ]/g," "));
var diff = (((new Date()).getTime() - date.getTime()) / 1000);
//console.log(diff);
if(myID == response3.owner.id && diff < 0 )
{
//console.log("found= " + myID);
var t = getImage(eventID);
if(t)
{
console.log("TRUE");
}
else
{
console.log("false");
}
}
}
});
}
function getImage(eventID){
//console.log("******eventID== "+eventID);
FB.api("/"+eventID+"/picture",
{
"redirect": false,
"type": "normal"
},function (response2) {
if (response2 && !response2.error) {
str="<br/><b>Pic</b> : <img src='"+response2.data.url+"'/>";
//console.log("response2.data.url= "+response2.data.url);
//str +="<b>name: </b>"+response3.name+"<br>";
document.getElementById("status2").innerHTML+=str;
return true;
}
else
{
return false;
}
});
}
As you mentioned the call to facebook's api is asynchronous meaning that you cannot be certain to know when the resulting data will come back from your request. You can work around and guarantee the order you're looking for by using a callback:
function readFacebook(id) {
console.log("myID= " + id);
}
function getMyID(cb) {
FB.api('/me', function(response) {
console.log("response.id= "+response.id);
cb(response.id);
});
}
getMyID(readFacebook);
What's happening here is that the call to FB.api accepts a callback that fires when the response comes back from the server. Since we're supplying our own callback to getMyID, we can use that to get access to response.id once the server responds.

Dojo using deferred functions to get data in ajax callback function

I have a function with a return however in the function there is an async request which holds the value that is suppose to be returned by the function. I understand with the nature of async request the function will complete and not return a value while waiting on the async function to complete.
I attempted to use dojo deferred functions to have my function PostInformation() to return a value within the ajax request callback. I am having some issues and i am not sure where my issue is. Under is my code:
Dojo Deferred Function
function PostInformation(){
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
def = dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function(err){
console.log(err);
def.reject(err);
}
});
def.then(function(data){
console.log('In the then function');
//alert('In the def.then and the results is : ' + data);
if(data == true){
return false;
}else{return true;}
},function(err){
return false;
alert('In the def.error and there has been an error ' + err);
});
//return the value of hasErrors here
};
Devdar, you are making heavy wether out of something quite simple. In particular, you don't need to loop through an object to access one of its properties, and the variable hasErrors is not really necessary.
Your code should simplify to something like this :
function PostInformation() {
var $containers = $("#container1, #container2");
var Employee = {
//data
};
return dojo.xhrPost({
url: 'hello',
content: Employee
}).then(function(data) {
data = JSON.parse(data);
var formErrors = data.formErrors;
if(formErrors.errors) {
$containers.each(function(i, c) {
$(c).children().each(function(wid) {
var val = formErrors[wid.id],
myWidget;
if(val) {
myWidget = dijit.byId(wid.id);
myWidget.validator = function() {
this.set("invalidMessage", val);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
//Send an enhanced error object down the "error" route
throw $.extend(formErrors, {
'message': 'PostInformation(): validation failure'
});
}
//Send the data object down the "success" route
return data;
});
};
PostInformation().then(function(data) {
console.log('PostInformation(): everything went OK');
//access/process `data` here if necessary
//and/or just display a nice "success" message to the user
}, function(err) {
console.error(err.message);
});
Barring mistakes on my part, this code should do everything you want and more. As with your own code, it processes the server's JSON response and returns a Promise, but that's where the similarity stops.
In your code, you seek to return a Promise which is eventually resolved with a boolean to indicate whether or not errors were detected. Whilst this will (if correctly written) meet your immediate needs, it is not the best Promise logic.
In my code, the Promise is resolved only if validation succeeds and rejected if validation fails for whatever reason. Not only is this logically correct behaviour for a Promise (success goes down the success route, and errors go down the error route) but as a bonus should (see note below) also allow you to pass more information to whetever function(s) eventually handle errors. I choose to pass the whole formErrors object enhanced with an error message, thus providing a great deal of freedom in the error handler to display/log/etc as much or as little as is appropriate, and with virtually no assumption inside PostInformation() as to what will happen subsequently. You currently believe that you will only read and act on the boolean formErrors.errors but it could be beneficial to pass as much error data as possible thus allowing yourself the freedom to change your mind at a later date without needing to change anything in PostInformation().
In this regard you can think of PostInformation() as an agent of the server-side service; and like that service, it can be written with incomplete knowledge (or maybe no knowledge at all) of how the (promise of) data/errors it delivers will be used by "consumer code".
NOTE: I have to admit that I'm not 100% familiar with Dojo's Promises, so I'm not sure that a JS plain object can be thrown in the way I indicate. I have found evidence but not proof that it can. For that reason, I am cautious above in saying "your code should simplify to something like this" Anyway, that issue aside, the principle of sending success down the success route and errors down the error route should still apply.
I'd suggest this where you create your own Deferred() object, return it from your PostInformation() function and then register .then() handlers on it so you can pick up the resolve or reject on your own Deferred object that happens inside the PostInformation() function.
The way you had it you were creating your own Deferred() object, but then immediately overwriting it with the xhrPost return result which meant def is now something else and you weren't returning your Deferred from PostInformation() so it can be used outside that function to track the progress.
function PostInformation() {
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function (err) {
console.log(err);
def.reject(err);
}
});
return def.promise;
};
PostInformation().then(function (data) {
console.log('In the then function');
// process data value here which will contain the value you resolved with
}, function(err)
// process an error in the ajax result here
});
I think this is more of an issue with design of the function then.
Since the xHR call is asynchronous, the postInformation shouldn't really return anything unless it's the Deferred object itself. An alternative option is to have postInformation do some sort of event publishing (dojo/topic), that other functions will subscribe to and know how to handle said events.

How to pass a parameter to a function in casperjs?

I have stored all the images url in an array, and am trying to test whether image has loaded properly. If you see the below code, i had to repeat few set of lines again and again. How can i write it to be generic?
casper.start()
var imagesArray = [];
imagesArray = ['https://www.google.co.in/images/srpr/logo11w.png',
'https://www.google.co.in/images/srpr/logo1w.png'];
casper.thenOpen(imagesArray[0], function () {
if (this.currentHTTPStatus === 404) {
this.warn(imagesArray[0] + ' is missing (HTTP 404)');
} else if (this.currentHTTPStatus === 500) {
this.warn(imagesArray[0] + ' is broken (HTTP 500)');
} else {
this.echo(' is okay (HTTP %s)');
}
});
casper.thenOpen(imagesArray[1], function () {
if (this.currentHTTPStatus === 404) {
this.warn(imagesArray[0] + ' is missing (HTTP 404)');
} else if (this.currentHTTPStatus === 500) {
this.warn(imagesArray[0] + ' is broken (HTTP 500)');
} else {
this.echo(' is okay (HTTP %s)');
}
});
casper.run(function() {
this.echo('Image loading test finished');
this.exit();
});
I tried the below method, calling a function but its throwing parser error, what am i doing wrong, or how can i proceed with it?
function checkImages(item){
if (this.currentHTTPStatus === 404) {
this.warn(item + ' is missing (HTTP 404)');
} else if (this.currentHTTPStatus === 500) {
this.warn(item + ' is broken (HTTP 500)');
} else {
this.echo(' is okay (HTTP %s)');
}
}
casper.thenOpen(imagesArray[0], function () {
this.evaluate(checkImages(imagesArray[0]));
});
casper.thenOpen(imagesArray[1], function () {
this.evaluate(checkImages(imagesArray[1]));
});
Thanks in advance.
Since all then* function are asynchronous step function that insert a step into the queue, you can call them in a loop. Since imagesArray is a native array, it can be iterated over by using Array.prototype.forEach which PhantomJS supports:
var imagesArray = [
'https://www.google.co.in/images/srpr/logo11w.png',
'https://www.google.co.in/images/srpr/logo1w.png'
];
casper.start();
imagesArray.forEach(function(imageUrl){
casper.thenOpen(imageUrl, function () {
if (this.currentHTTPStatus === 404) {
this.warn(imageUrl + ' is missing (HTTP 404)');
} else if (this.currentHTTPStatus === 500) {
this.warn(imageUrl + ' is broken (HTTP 500)');
} else {
this.echo(' is okay (HTTP %s)');
}
});
});
casper.run();
A simple for loop would have sufficed, but then you would have a problem with the imagesArray[i] inside of thenOpen. The i variable would never change, because every step is executed after the loop finished executing. So every imagesArray[i] would show the last url. Because JavaScript has function level scope the url bound to each iteration and never changes afterwards.
As a reminder, think of the evaluate() method as a gate between the CasperJS environment and the one of the page you have opened; everytime you pass a closure to evaluate(), you’re entering the page and execute code as if you were using the browser console. So you can't use evaluate on checkImages.
Use echo like this :
casper.thenOpen(imagesArray[0], function () {
this.echo(checkImages(imagesArray[0]));
});
casper.thenOpen(imagesArray[1], function () {
this.echo(checkImages(imagesArray[1]));
});
You don't have any need for thenOpen in this test case, since you only want to verify response code. you CAN do it that way, but it's incredibly wasteful of time/resources. this is how I achieved the same goal:
casper.test.begin('link tester', 73, function(test) {
casper.start(url);
getLinks = function(){
links = this.evaluate(function(){
var links = document.getElementsByTagName('a');
links = Array.prototype.map.call(links,function(link){
return link.getAttribute('href');
});
return links;
});
}
casper.then(getLinks);
casper.then(function(response) {
for (q = 0; q < links.length; q++) {
if (response == undefined || response.status >= 400) {
this.test.fail("URL " + links[q] + " failed with response code " + (response.status));
} else {
this.test.pass((response.status + " ---- " + links[q]));
}
}
});
the only caveat with this would be that you can only have 1 failure per casper function. if you are testing 100 URLs on a page, and you fail on the 4th one, you will have to fix that one before you can see if the others failed. thus, you would need to nest a casper.then() within your if statement. In case you were wondering, it would look like this:
casper.then(function(response) {
links.forEach(function(link){
if (response == undefined || response.status >= 400) {
casper.then(function() {
this.test.fail("URL " + link + " failed with response code " + (response.status));
})
} else {
this.test.pass((response.status + " ---- " + link));
}
});
});

Wait for Json call to be completed in javascript

I am using the below json call in my javascript method
function go123(){
var cityName = "";
var temp = $.getJSON("https://abc.in/api/city?callback=?", args,function (data) {
if (data.properties.city != null){
cityName = data.properties.city;
check = true;
} else {
cityName = "NaN"
}
}); // end of my Json Call.
// my validation is done below
if(cityName != "NaN"){
return false;
} else {
// here I except the cityName to not be "" but be some value which is set as :cityName = data.properties.city;
return true;
}
} // end of my function
Now what problem I am facing is that before my Json call is compelete the next set of statements ( in the code below the line "// my validation is done below " ) is already executed.
I want to get the values set in my json call (cityName) and only once when the call is completed then only I want the next set of statements to be executed.
Please help me on this. Any advice/ideas/suggestions will be highly appreciated ! Thanks.
The function you passed into $.getJSON() is the callback run when the function completes successfully. All else being equal, stick the "rest of it" inside that method. If you can't do so, what you're after is called a jQuery Deferred. See http://www.erichynds.com/jquery/using-deferreds-in-jquery/ and http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ for code that looks like so:
var req = $.getJSON('blah', 'de', 'blah');
req.success(function(response){
// The request is done, and we can do something else
});
AJAX calls are asyncrhonous. They don't wait for the reply. They operate in the background and execute the code that follows it immediately after the call. Therefore, the data received in getJSON is not yet there when the operations below it are executed.
You can put the operations you want in the callback so that they get executed when the data is revceived:
function go123(callback){
var temp = $.getJSON("https://abc.in/api/city?callback=?", args,function (data) {
//execute the callback, passing it the data
callback(data);
});
}
//when you call go123, it get's back the result:
function goBefore123(){
//get our JSON
go123(function(data){
//when we get our data, evaluate
if (data.properties.city != null){
cityName = data.properties.city;
check = true;
alert('executed after returned');
afterCall();
} else {
cityName = "NaN"
}
});
alert('i am executed before anything else');
}
function afterCall(){
alert('im also executed after');
}
Calling an external url will take too much time, wait for the result
Check below
var jqxhr = $.getJSON("example.json", function() {
alert("success");
})
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
http://api.jquery.com/jQuery.getJSON/
.success
http://api.jquery.com/jQuery.getJSON/

Categories

Resources