Change function on javascript prototype - javascript

I want to change the XMLHttpRequest send function so that a function is called before the request is made and after the request is complete. Here is what I have so far:
var oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
//this never gets called
oldOnReady = this.onreadystatechange;
this.onreadystatechange = function() {
oldOnReady();
ajaxStopped();
}
ajaxStarted();
// according to http://www.w3.org/TR/XMLHttpRequest/
// there's only ever 0 or 1 parameters passed into this method
if(arguments && arguments.length > 0) {
oldSend(arguments[0]); //gets to here, calls this method, then nothing happens
} else {
oldSend();
}
}
function ajaxStarted() {
ajaxCount++;
document.getElementById("buttonClicky").innerHTML = "Count: " + ajaxCount;
}
function ajaxStopped() {
$("#isRunning")[0].innerHTML = "stopped";
ajaxCount--;
document.getElementById("buttonClicky").innerHTML = "Count: " + ajaxCount;
}
However, I'm doing something wrong here because once it hits the oldSend() call, it never returns or triggers the onreadystatechange event. So I must be doing somethingclickCount wrong here. Any ideas? I set a breakpoint and it gets hit just fine when I call this:
$.ajax({
type: "GET",
url: "file.txt",
success: function(result) {
//this never gets called
document.getElementById("myDiv").innerHTML = result;
}
});
So my new function is getting called. I guess just don't know how to call the old function. Any ideas on how to fix this code so that the Ajax Request is actually made and my new callback gets called?
Note: I'm aware of the JQuery events that essentially do this. But I'm doing this so I can get it to work with any Ajax call (Mootools, GWT, etc). I am just happening to test it with Jquery.

You need to call old functions in the context of this.
E.g.: oldSend.call(this)

Related

Functions within a loop using requirejs

I'm having an issue with calling functions within a loop across different modules using requirejs. The function call within the loop resides in module A and executes a function in module B that fires off an Ajax request using jQuery. Each iteration of the loop fires off a different request with different arguments being passed to module B's function that fires off the Ajax request. When the success function of the Ajax request executes, I find that all my argument values are always the values of the last Ajax call made, for all 4 separate Ajax calls.
I've done some googling and it sounds like this is a pretty common problem when executing a function within a loop. The fix tends to be to break out the function call into a different function, creating a different scope. Since my loop and Ajax calls are in 2 different modules I had assumed this would solve that issue, however it still persists.
I've tried some solutions in other stack overflow posts like:
JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself and How to pass parameter to an anonymous function defined in the setTimeout call? without success. Anyone have any idea?
Sample code for loop module A:
define(["mpos"],
function(mpos){
var monitor = {
startMonitoring : function(poolObj){
// Start Monitoring
$.each(mpos.msgs, function(action,callback){
poolObj.action = action;
mpos.sendApiRequest(poolObj,action,callback);
});
}
};
return monitor;
}
);
Sample code for Ajax module B - this module is referenced as mpos in module A
define(["mule","constants"],
function(mule,constants){
var mpos = {
sendMessage : function(postData,callback,$poolOut){
return $.ajax({
'type':'post',
'url':constants.URLS.proxy,
'data':{'url':postData},
success : function(data){
// if we have $poolOut we know this is a mpos call
if($poolOut != undefined){
var keys = Object.keys(data);
// add poolOut to data
data.poolOut = $poolOut;
var poolObj = $poolOut.data('poolObj');
if(poolObj){
var action = poolObj.action;
console.log(poolObj,action);
if(action){
if(action == "getuserstatus"){
mule.registerPool(poolObj);
}
} else {
log.error("No action on poolObj while attempting to calculate the need for a registerPool call");
}
}
}
// parse data
callback.apply(this, data);
},
error : function(x,h,r){ ... },
dataType : 'json'
});
},
sendApiRequest : function(poolObj,action,callback){
var url = poolObj.url + '&page=api&action=' + action;
var $poolOut = constants.cache.monitorOutput.find('.pool-out.' + poolObj.id);
var dfd = mpos.sendMessage(url,callback,$poolOut);
$.when(dfd).always(function(){
var refreshTimer = setTimeout(function(){
if(constants.state.monitorEnabled){
mpos.sendApiRequest(poolObj, action, callback);
}
}, poolObj.refreshRate);
});
},
msgs : {
"getuserstatus" : function(data){ ... },
"getpoolstatus" : function(data){ ... },
"getuserworkers" : function(data){ ... },
"getuserbalance" : function(data){ ... }
}
};
return mpos;
}
);
Thanks!
NOTE: I am assuming that $poolOut.data('poolObj') is being used to find the poolObj instance passed in the call to startMonitoring, and will return the same instance each time.
You state, "Each iteration of the loop fires off a different request with different arguments being passed to module B's function that fires off the Ajax request."
This statement is not correct. Each iteration fires off a different request with the first argument poolObj being the same in each iteration.
In your .each iteration, you are overwriting the value of poolObj.action before each call to sendApiRequest.
In the AJAX success handler, which is likely invoked after all iterations have completed, the value of poolObj.action will have the value you set it to in the last iteration.
To solve this, I think you need to pass action as a parameter to sendMessage, too, so that a separate value is being stored in the closure for each function call.
var mpos = {
sendMessage : function(postData,action,callback,$poolOut){
return $.ajax({
'type':'post',
'url':constants.URLS.proxy,
'data':{'url':postData},
success : function(data){
// if we have $poolOut we know this is a mpos call
if($poolOut != undefined){
var keys = Object.keys(data);
// add poolOut to data
data.poolOut = $poolOut;
var poolObj = $poolOut.data('poolObj');
if(poolObj){
// action is not guaranteed to be the same as poolObj.action here,
// since poolObj.action may have changed since this function was first called
console.log(poolObj,action);
if(action){
if(action == "getuserstatus"){
mule.registerPool(poolObj);
}
} else {
log.error("No action on poolObj while attempting to calculate the need for a registerPool call");
}
}
}
// parse data
callback.apply(this, data);
},
error : function(x,h,r){ ... },
dataType : 'json'
});
},
sendApiRequest : function(poolObj,action,callback){
var url = poolObj.url + '&page=api&action=' + action;
var $poolOut = constants.cache.monitorOutput.find('.pool-out.' + poolObj.id);
var dfd = mpos.sendMessage(url,action,callback,$poolOut);
$.when(dfd).always(function(){
var refreshTimer = setTimeout(function(){
if(constants.state.monitorEnabled){
mpos.sendApiRequest(poolObj, action, callback);
}
}, poolObj.refreshRate);
});
},
msgs : {
"getuserstatus" : function(data){ ... },
"getpoolstatus" : function(data){ ... },
"getuserworkers" : function(data){ ... },
"getuserbalance" : function(data){ ... }
}
};

Jquery Ajax/getJSON Javascript Question

I am still trying to figure all this out and I am coming across a really weird error.
I was using getJSON but after searching for solutions to this problem, I found that it was better to try to use the AJAX function (for error capturing -> which isnt firing).
Using breakpoints in firebug, if I go slowly through the running code, it works (mostly) fine (just need to change some coordinates for better drawing). But if I let it run at normal speed, it attempts to do the callback before the json object is returned. The firebug console says everything works ok (code 200), but when examining the jobj inside ship object/function it appears to be "undefined or null"
Following the breakpoints, the ajax calls seem to be going to "error" and not "success". But it isn't firing the alert...
Also, the response takes like 300-500ms.... is that normal? or do I need to find a better server?
Edited Code:
var init = (function(){
thisplayer = new player();
jQuery.ajax({type: "GET", url: "shipdata.php", processData: true, data: {shipid:1}, dataType: "json",
success: function(json) {
var pship = new ship(json);
player_ship = $.extend(thisplayer, pship);
starfield = new starfield();
for(var i = 0; i < player_ship.enemytotal; i++) {
$.ajax({
type: "GET",
url: "shipdata.php",
processData: true,
data: {shipid:Math.round((Math.random()*2+2))},
dataType: "json",
success: function(json) {
var enemy = new ship(json);
game.enemies.push(enemy);
},
error: function(x,y,z) {
// x.responseText should have what's wrong
alert(x.responseTest);
}
});
}
game.initialized = true;
},
error: function(x,y,z) {
// x.responseText should have what's wrong
alert(x.responseTest);
}
});
})
..............................
var ship = (function(json){
var self = this;
jobj = jQuery.parseJSON(json.responseText);
self.height = jobj.height;
self.width = jobj.width;
self.xinit = jobj.xinit;
self.yinit = jobj.yinit;
self.speed = jobj.speed;
self.weapons = jobj.weapons;
self.maxlasers = jobj.maxlasers;
self.imagesrc = jobj.imgurl;
self.lasers = [];
self.x = self.xinit;
self.y = self.yinit;
JSON being sent in:
{"height":75,"width":50,"xinit":275,"yinit":525,"speed":3,"weapons":[1,2],"maxlasers":2,"imgurl":"images\/ship.png"}
Live Demo:
http://www.schennshome.net/medicalmmj/practice/index.html (The code is far from being perfect, Im running through it to try and catch the various errors before animating, but cant get past this.)
I've dug through your source code, and the problem is not actually shown in your question. The problem is with this line, which follows your Ajax call:
player_ship = $.extend(thisplayer, game.pship);
game.pship refers to the data returned by the ajax call, but since this is asynchronous, the above line will be evaluated first, which means game.pship will not be defined.
To fix this, you need to include all of the code in your init function that is currently below the ajax call directly in the success callback. This will prevent the code from being evaluated until the ajax call has returned.
The reason that it works with breakpoints is that this interrupts evaluation, which allows the ajax call to complete before game.pship is referenced.
Edit
I'm now getting an error on line 489, stating that player_ship is undefined. This is again because of the evaluation order of async code. The problem is that player_ship is being defined inside the ajax function in init now, but is being referenced in gameLoop, outside of this callback.
This is how I would rewrite gameLoop:
var callback = function() {
game.canvas.clearCanvas();
drawStarfield();
if(player_ship.alive && game.initialized && !(game.loading)) {
drawPlayer();
drawLaser();
drawEnemies();
}
};
if(game.initialized==false) {
init(callback);
} else {
callback();
}
And then amend init to accept a callback method which is called at the bottom of your success callback. This way, if the game has not been initialized (and player_ship is not yet defined), it will be executed after the ajax call.

Why does this function not return JSON string?

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.

jQuery $.post() in recursive way (loop)

I learn jQuery and don't understand this situation:
When running this code in debug mode all work well. But when running this code normal, calback function don't starts. Why?
In non debug mode I have -> "Start" -> "End 10"
Browser: Google Chrome.
var nrPost = 10;
$("#buttnX").click(function() {
alert("Start");
GoPosts();
End();
});
function End() {
alert('End ' + nrPost);
};
function GoPosts() {
$.ajaxSetup({async:false});
var url = "http://......";
var data = { ... };
$.post(url, data, Callback, 'json');
};
function Callback(response) {
if (response.error) {
return;
}
nrPost--;
if (nrPost > 0) [
GoPosts();
} else {
return;
}
};
You had an extra }; in your code. I changed it around a bit to use jQuery and put it up on jsfiddle.
http://jsfiddle.net/rH8RV/19/
It should alert: "Start" and then "End 10", that's correct based on how you wrote your code. Were you expecting anything else?
I don't know what you're planning to do with your recursive implementation, but if that's all, you could actually do this:
function startLoop(nrPost) {
// No need to put this in a loop
$.ajaxSetup({ async: false });
for (var i = 0; i < nrPost; i++) {
alert('Start ' + i);
var url = 'http://......';
var data = {};
$.post(url, data, function (response) {
if (response.error)
return;
alert('End ' + i);
}, 'json');
}
}
$('#buttnX').click(function () { startLoop(10) });
Hope that helps!
I imagine you are expecting the display to be:
"Start"
"End 0"
This is unlikely to work with your solution.
Your Ajax call $.post(url, data, Callback, 'json'); is asynchronous. This means that once the $.post method returns, the request is sent to the URL you have provided. However, Callback is not called until JQuery receives the answers. What happens immediately is that GoPosts terminates and the program continues. It comes back to line 5 of your code, inside the anonymous function in your click handler. At that point, End() is called and alerts "End 10".
You probably want to put your call to End in Callback instead:
function Callback(response)
{
if (response.error)
{
return;
}
nrPost--;
if(nrPost>0)
GoPosts();
else
{
End(); // You only want to end once you have made you nrPost calls to GoPost
return;
}
};

jquery $.ajax() and its success callback - where is it returning to?

Where does the jquery ajax success callback return to?
I have written a request method that makes an ajax call, detects if I have supplied a callback or returns the datanode of the response XML.
Request Method:
function request(request, dontRefresh)
{
var requestXML = composeRequestXML(request);
$.ajax({
url: 'someProcessor.php',
type: 'POST',
cache: false,
async: dontRefresh,
timeout: 5000,
data: "query="+requestXML,
success: function(response)
{
//parses xml into a js object
var responseObj = parseResponseXML(response);
if(request.callback){
request.callback(responseObj);
} else {
// responseObj.response[0].data[0] is the data
// node of the response Obj.
// this is what i see being the problem -
// I DON'T KNOW WHERE THIS IS RETURNED TO!!
return responseObj.response[0].data[0];
}
}
});
}
This request would use the callback
var requestObj = new Object();
requestObj.callback = function(responseObj){someCallbackFunction(responseObj);};
requestObj[0] = new Object();
requestObj[0].module = "someModule";
requestObj[0].action = "someModuleMethod";
request(requestObj);
//results are returned to the function someCallbackFunction()
This is an example of what i'd like to accomplish
var requestObj = new Object();
requestObj[0] = new Object();
requestObj[0].module = "userManager";
requestObj[0].action = "GET_USERID";
var userId = request(requestObj, false); //make the request asynchronous
I've tried returning the $.ajax() function itself... like so:
function request(request, dontRefresh){
return $.ajax({/*...options...*/);
}
But this bypasses the xml parser I have developed and returns the XHR object. I would like to use this kind of technique to register variables. So essentially...
I will be using this method with a callback or setting a variable with it.
It gets returned to jquery, and jquery discards it. If you want to make your code stop until something has been loaded, use synchronous ajax. But that makes the page irresponsive until the ajax request is complete, so please don't do it!
Example of synchronous ajax (without jquery):
var ajax=new XMLHttpRequest();
ajax.open("GET", url, false);
ajax.send(null);
return ajax.responseText;
Note: For IE compatibility, this gets a little bit more complicated, this is just a proof of concept. And this would be the jquery way of doing it: How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?
From your perspective, the function does not return to anywhere. Return values are lost.
The key with asynchronous processing is that you handle any data associated with an event in the event handler, or pass it on from there.
/* ... */
success: function(response)
{
//parses xml into a js object
var responseObj = parseResponseXML(response);
if(request.callback){
request.callback(responseObj);
} else {
/* do something with the data */
setUserId(responseObj.response[0].data[0]);
}
}
Where setUserId() is a function that does something useful, as soon as the user ID is available.
As an aside, you should probably not use responseObj.response[0].data[0] without making sure first that that value actually exists.

Categories