jQuery Ajax: Sucess Response parameter overwriting - javascript

I am having a strange problem where the response param of 1st ajax call is being overwritten by the 2nd call's param.
Code is:
http://pastebin.com/degWRs3V
When both drawDonutForExternalLogin & drawDonutForExtUser are called consecutively,the response variable of the later request(data param of success handler) overwrites the data param of 1st request.
The calls do complete almost at the same time always but when there is a difference this problem doesn't occur.The data set is also fine when the 2nd function is invoked from the success handler of 1st function.
Why the data param becomes identical when the calls are consecutive and finish at the same time?
I tried debugging the server side code by placing breakpoints but that also provides the delay between ajax requests thereby yielding correct result.
Any ideas please?

Copied from stackoverflow.com/questions/5583478/java-servlets-ajax-requests-come-back-with-mixed-responses to OP's request :
The likely cause is that the servlets are not written to be thread
safe. Note that the object that contains the servlet methods may be
used to respond to many simultaneous requests. If that method uses a
class level variable to create the response, then requests will appear
to get 'mixed up'.
So.. Request #1 comes in, is assigned to an instance of Servlet,
Instance #1
The appropriate method is invoked on Instance #1, which starts using a
class variable to calculate the result. Instance #1.myVariable =
"Blah"
Now, Request #2 comes in, is also assigned to Instance #1
Again, the appropriate method is invoked on Instance #1, which sets
Instance #1.myVariable ="Foo"
.. in the mean time the first request completes, and returns Instance
1.myVariable... "Foo"!
.. and then the second request completes, and also returns "Foo".

Related

Use Remote Service (RPC) in XPages

I am trying to update a document using rpc service.
I have an xpage with a button. I want to click that button and by using CS javascript to setInterval and update a document field every 5 seconds.
I used the remote service control and the code is this:
<xe:jsonRpcService id="jsonRpcService1" serviceName="heartBeat">
<xe:this.methods>
<xe:remoteMethod name="send">
<xe:this.script><![CDATA[var db = session.getCurrentDatabase();
var heartView = db.getView("Heartbeats");
var doc:NotesDocument = heartView.getFirstDocument();
var vl = doc.getItemValueString();
if(vl==""){
doc.replaceItemValue("dummyH","z");
}else{
doc.replaceItemValue("dummyH",vl+"z");
}
doc.computeWithForm(false, false);
doc.save();]]></xe:this.script>
</xe:remoteMethod>
</xe:this.methods></xe:jsonRpcService>
The code of the button is this:
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[setInterval(function(){heartBeat.send()},3000);]]></xp:this.script>
</xp:eventHandler></xp:button>
It doesnt work. I get no error but i also get no updates in the document... What is wrong in the code?
UPDATE
if i replace rpc script with a simple print("aaaaa") it works perfectly (i also followed the suggestions of Tim in the answer below, for my client side code).
when i use again my previous code i get the following javascript error:
Unable to load /Databases/Test/Mike/my1.nsf/RPCpage.xsp/mm?$$viewid=!dqducrahog! status:400
how can i access the database and documents from a remote service?
The syntax of RPC calls is slightly unusual; your call to heartbeat.send(), for example, does not actually call the remote send method. Rather, it returns a handle on a remote method descriptor... to actually call the remote method, you need to add a callback:
var remoteMethod = heartbeat.send();
remoteMethod.addCallback(function(response){
// handle whatever came back from the server
});
If, for instance, you designed your remote method to return whether or not the heartbeat was successful, a more complete example would look like this:
var heartbeatInterval = 3000;
var periodicHeartbeat = function() {
var remoteMethod = heartbeat.send();
remoteMethod.addCallback(function(response){
if (response.stillAlive) {
setTimeout(periodicHeartbeat, heartbeatInterval);
}
});
}
setTimeout(periodicHeartbeat, heartbeatInterval);
It's generally recommended to use setTimeout to initially schedule a deferred function, and then call setTimeout again from within that deferred function to schedule its own next execution, instead of using setInterval.
In this use case, however, this is particularly true because each remote method call is asynchronous, so with setInterval, you would eventually end up with request overlap, because each call requires at least a few milliseconds to complete.
Additionally, the preferred pattern of scheduling the next execution from inside the current allows you to check what the server sent back to determine whether to even bother continuing to send subsequent requests. Right now you're not returning any value from your remote method; if you change just the last line to:
return { stillAlive: doc.save() };
...then that JSON object will be automatically passed to your callback function as its first argument. Taking another look at one line from the prior example:
if (response.stillAlive) {
...so the RPC call only reschedules itself if the prior call succeeded. This probably isn't the precise behavior you want, but given that you can return data from the remote method, and the data that was returned is passed to your callback function, you can design a call and response approach that best fits your business specifications for this functionality.
Having said all that, you may want to take a look at the keepAlive component from the XPages Extension Library... it doesn't store heartbeat data in Domino documents, but if all you're trying to do is prevent idle sessions from expiring, it's a much simpler solution.

Javascript window.location calls getting lost?

I am having some trouble with a bit of code. I have a function that does some stuff to some data, calls a remote system (activating a script on that system and passing in the data), and then makes another call to the same system to activate a different script (which acts on the data saved above). The problem is that the 1st call to the remote system appears to get lost in the execution.
This is being run in Safari, uses jquery; the function is tied to a button click, which is defined in the javascript code with an onclick function (i.e. it is not defined in the html button definition).
Here's a rough breakdown of the function (cleaned out for viewing purposes - I hope I left enough to make it clear):
function compareJSON() {
// loop through the objects, testing and changing data
// ...
dataSession=({ //build object for output });
$.each( dataSession.chapters , function( indexC, value ) {
//compare objects to some others, testing and changing data
});
// ...
//Call remote script on other system
urlString="url://blah.dee.com/Blar?script=SaveJSON&$JSONobject=";
window.location= urlString + JSON.stringify(dataSession);
//Call remote script on other system
window.location="url://blah.dee.com/Blar?script=EditJSON";
}
The last three lines of code are the two calls. It uses the window.location to actually trigger the remote system, passing the data through the URL. But I need BOTH scripts to get called and run. It appears that only the LAST script in the sequence ever gets run. If I switch them around it remains whatever is in last place.
Is there something about the window.location that doesn't actually process until the end of the function?
This script actually used to be a series of separate function calls, but I figured I was running into asynchronous execution that was causing the various script calls to not register. But once I put the code into this single function, it was still happening.
Any clues would be helpful.
Thanks,
J
Modifing the value of window.location is reserved exclusively for instances in which you'd like to cause a browser redirect.
It looks like you want to trigger a page request instead. You say you already have jQuery loaded, if so, you can trigger such a request using jQuery.get or a similar function.
For example:
// Loads the myscript.php page in the background
$.get('myscript.php');
// You can also pass data (in the form of an object as the second argument)
$.get('myscript.php', { name: "John", time: "2pm" });

AJAX, client-side JavaScript processed before server-side JavaScript?

I have a question as to how client-side code is processed along with server-side responses.
I have some code (too complex and long to post here) that when it runs, calls a function which runs some server-side code using a HTTPRequest Object, and returns a string to the page that the function was called from. For some reason, I think that the client-side code is being processed, the string is returned (too late) and my code is failing because of it. For example, I call my function with the HTTPRequest, next line I try to display the returned value (the string from the HTTPRequest) in an alert, and the alert shows up as blank. A few lines later in the code though, the same alert shows up with the value returned. So, basically, I am under the impression that the first client-side alert is being processed so that it displays a string which has not yet been returned, whereas the second alert was processed later, (ergo. giving the server time to process the request) and displaying the requested string. Does this theory sound logical? Will client-side code run, regardless of whether or not a HTTPRequest was completed? If so, are there any ways to prevent the client-side code from executing until a response is received from the server?
An HTTP Request is asynchronous. That means your code is going to send it and continue on with it's execution. You need to set up a callback function that takes the data returned by the XHR request, and uses that data in some way.
You need to bind an anonymous function to the onreadystatechange event of the XmlHttpRequest object so:
//xhr is an instance of the XmlHTTPRequest object that you have opened correctly
xhr.onreadystatechange = function(){ //4 means the request was successful
if (xhr.readyState === 4){
//Your code here
}
}
You need to make sure that your bit of code that attempts to display / act on the returned value is within the scope of the ajax routine. That's the only way to guarantee that the response will not be acted upon until the request has been completed (whether successfully or not). For example, if you are using jQuery:
CORRECT
jQuery.get('ajax/ajax.getSomeData.php',{id:id}, function(data) {
$('#myDIV').html(data);
});
INCORRECT
jQuery.get('ajax/ajax.getSomeData.php',{id:id}, function(data) {});
$('#myDIV').html(data);

javascript outside of scope

Based on chrome developer tools a breakpoints I think I'm dealing with a scope issue I can figure out. Is it the way I define the function? The script below is an include js file and the array ' timeStamp I want available for use in other functions without having to call my loadData function everytime.
The timeStamp array goes undefined once it leaves the for loop before it even leaves the function.
var timeStamp = []; // Want this array to be global
function loadData (url){
$.getJSON(url, function(json) {
for (var i=0;i<json.length;i++){
timeStamp.push(json[i].TimeStamp);
}
console.log(inputBITS); //returns the value
});
console.log(inputBITS); //undefined
}
Thank you for anyhelp
It looks like the issue is that getJSON is asynchronous. When it executes and finishes and your code continues on, it indicates only the START of the networking operation to retrieve the data. The actual networking operation does not complete until some time later.
When it does complete, the success handler is called (as specified as the second argument to your getJSON() call) and you populate the timeStamp array. ONLY after that success handler has been called is the timeStamp array valid.
As such, you cannot use the timeStamp array in code that immediately follows the getJSON() call (it hasn't been filled in yet). If other code needs the timeStamp array, you should call that code from the success handler or use some other timing mechanism to make sure that the code that uses the timeStamp array doesn't try to use it until AFTER the success handler has been called and the timeStamp array has been populated.
It is possible to make some Ajax calls be synchronous instead of asynchronous, but that is generally a very bad idea because it locks up the browser during the entire networking operation which is very unfriendly to the viewer. It is much better to fix the coding logic to work with asynchronous networking.
A typical design pattern for an ajax call like this is as follows:
function loadData (url){
$.getJSON(url, function(json) {
// this will execute AFTER the ajax networking finishes
var timeStamp = [];
for (var i=0;i<json.length;i++) {
timeStamp.push(json[i].TimeStamp);
}
console.log(timeStamp);
// now call other functions that need timeStamp data
myOtherFunc(timeStamp);
});
// this will execute when the ajax networking has just been started
//
// timeStamp data is NOT valid here because
// the ajax call has not yet completed
// You can only use the ajax data inside the success handler function
// or in any functions that you call from there
}
And here's another person who doesn't understand basic AJAX...
getJSON is asynchronous. Meaning, code keeps running after the function call and before the successful return of the JSON request.
You can "fix" this by forcing the request to be synchronous with an appropriate flag, but that's a really bad idea for many reasons (the least of which is that you're violating the basic idea of AJAX). The best way is to remember how AJAX works and instead put all your code that should be executed when the AJAX returns, in the right place.

How do I write a JS function to do something and then return once that process is done?

I'm adding some functionality to an existing function. I need to insert an additional step in the middle of the current routine. I know how to go to the 2nd function but I don't know what to do to return to the main function once the 2nd routine completes.
function step1(){
perform ajax call to see if student is assigned to a project
step1_subfunction()
// wait here until step1_subfunction is done
do some more stuff with response from user
}
function step1_subfunction(){
prompt user via jQuery dialog, 'Add or move employee to the project?'
// return to step1 with answer returned from user and resume
}
I'd google this but I don't know if this "process" has a name. Back in my days of COBOL, we called this gosub.
UPDATED:
Step1 performs an ajax call to see if an employee has been assigned to a project. If the response.status = 'Assigned', the user will be asked via a jQuery dialog box, "Do you want to copy or move the employee to this project?". The jQuery dialog box will be step1_subroutine. The answer will be passed back to the step1 function. The remaining part of step1 will simply be to place a value in a hidden text field of "copy" or "move".
What you have will perform what you are describing, but may not make the data from the user available to function step1() without a return in function step1_subfunction(). Below I've modified your example code to demonstrate the passing of values back.
function step1(){
//do some stuff
var returnValFromFunction = step1_subfunction();
// wait here until step1_subfunction is done
// Now use returnValFromFunction, it contains the information from the user
do some more stuff with response from user
}
function step1_subfunction(){
prompt user for some information
// return to step1 with information returned from user and resume
return userResponse;
}
What you've written should work - javascript is single-threaded, so have you tried it?
Javascript doesn't have subroutines specifically, just create a function that returns and ignore the result, as you have done. When the second routine completes, the scope and execution will continue in the first function.
just do nothing.
what you are trying to achieve is just a "function call"
so it will automatically return to it's caller "stack frame" once executed.
You can make the ajax object synchronous - IE, no code will continue until it gets a response. It's the third parameter of open (true is asynchronous, false is synchronous).
xmlhttpobject.open('POST', 'url', false);
There are cases where a synchronous call is fine but it should always be avoided if possible.
The other alternative, which would likely require some logic changes in your code but would be better off in the long run, is to bind the onReadyStateChange event. This fires every time the state of the xmlHttpRequest object changes - you can check to see if the status is 200 and the readystate is 4 to make sure the request is done and completed successfully.
Here's a better reference. Good luck.

Categories