overwitting the XMLHttpRequest causes the load failure - javascript

I am trying to count the number of ajax calls. I want to do this to wait until all the ajax calls return.
I have written the following code:
var xmlreqc=XMLHttpRequest;
XMLHttpRequest = function() {
this.xhr = new xmlreqc();
return this;
};
XMLHttpRequest.prototype.open = function (method, url, async) {
return this.xhr.open(method, url, async); //send it on
};
XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
this.xhr.setRequestHeader(header, value);
};
XMLHttpRequest.prototype.getAllResponseHeaders = function() {
console.log( this.xhr.getAllResponseHeaders());
return this.xhr.getAllResponseHeaders();
};
XMLHttpRequest.prototype.send = function(postBody) {
// steal the request
nRemAjax++;
// do the real transmission
var myXHR = this;
this.xhr.onreadystatechange = function() { myXHR.onreadystatechangefunction();};
this.xhr.send(postBody);
};
XMLHttpRequest.prototype.onreadystatechangefunction = function()
{
try {
this.readyState = this.xhr.readyState;
this.responseText = this.xhr.responseText;
console.log(this.xhr.responseText); // this line log json data though
this.responseXML = this.xhr.responseXML;
this.status = this.xhr.status;
this.statusText = this.xhr.statusText;
}
catch(e){
}
if (this.onreadystatechange)
this.onreadystatechange();
//do my logging
if (this.xhr.readyState == 4)
{
nRemAjax--;
// only when done steal the response
consoleLog("I'm finished");
}
};
I have injected above code into the browser.
This works fine for most of the Websites, except for http://demo.opencart.com/index.php?route=account/register.
For some reasons, the Region/state field is not loaded properly on page load.
What I found that the Region/Field is populated with JSON data that has been send as a response from ajax call.
Please note that I am adding this script in the head.

Related

Using promise to call Ajax without duplicating code

is this possible? I want to write an ajax function, that I do not want to duplicate it. Pass it different parameter which are locations to different files. Then use the promise to make them into one object. I would possible use the spread operator. is this possible.
var myFuncCalls = 0;
let promiseAjax = new Promise (function ( resolve,reject) {
//possibly use a for look to grab the number of times the loadDoc was called then call the same function and send it to may be an array?
function loadDoc(location) {
myFuncCalls++;
console.log("loadDoc was called :" + myFuncCalls);
var xyz = new XMLHttpRequest();
xyz.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
//console.log(this.responseText)
resolve(this.responseText);
}
};
xyz.open("GET", location, true);
xyz.send();
}
loadDoc("/_js/someitems.json");
loadDoc("/_js/someMoreItems.json");
})
// then grab all that stuff and make one single object using spread operators
promiseAjax.then(function (fromResolve){
// JSON.parse(fromResolve);
var newObj = JSON.parse(fromResolve);
console.log(newObj);
})
with Promise.all and Object.assign,
function loadDoc(location) {
return new Promise((resolve, reject) => {
var xyz = new XMLHttpRequest();
xyz.onreadystatechange = () => {
if (this.readyState == 4 && this.status == 200) {
resolve(JSON.parse(this.responseText));
} else {
// resolving with empty object to avoid breaking other fetch if one failed
resolve({});
}
};
xyz.open("GET", location, true);
xyz.send();
});
}
const loadDocs = (paths) => Promise.all(paths.map(path => loadDoc(path))
.then(results => {
// combine all result into single object
return Object.assign({}, ...results);
}));
// example
loadDocs([
"/_js/someitems.json",
"/_js/someMoreItems.json"
]).then(function(finalCombinedObject) {
// other logic here
});
Use Promise.all() to get the two calls together and so what ever you want with the array of the data you resolved.
function loadDoc(location) {
return new Promise (function ( resolve,reject) {
var xyz = new XMLHttpRequest();
xyz.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
resolve(this.responseText);
}
};
xyz.open("GET", location, true);
xyz.send();
});
}
const urls = ["/_js/someitems.json", "/_js/someMoreItems.json"]
Promise.all(urls.map(url=>loadDoc(url))).then(responses =>
console.log(responses);
)
I think the easiest thing would be to define async functions, which return promises and can be easily passed around and reused.
You can do something like:
async function loadFile(file) {
...
return {...fileJSON};
}
async function loadFiles() {
const file1JSON = await loadFile('file1');
const file2JSON = await loadFile('file2');
return {...file1JSON, ...file2JSON};
}
loadFiles().then((combinedJSON) => {
...
})
These functions can take arguments and be reused like any other function.
This kind of behavior can archived with Promise.all Promise.all white the use of async+await async and the use of more state of the art calls (fetch) makes the code looks cleaner
async function loadAll(docs) {
return Promise.all(docs.map(async doc => {
const result = await fetch('http://example.com/movies.json');
return result.json();
}));
}
(async function() {
const responses = await loadAll(["/_js/someitems.json", "/_js/someMoreItems.json"]);
console.log(responses);
})();
Note: await can only be used from an async function.
Note2: the code is untested
Yes, youcan send the URL, any parameters, even the type of AJAX call (POST, GET, etc), to the method, then use it to build the call. This way, you can reuse the same method to do anything and everything you need to do from your client with a "simple" method call.
All code in this Answer is copied from the below link.
https://medium.com/front-end-weekly/ajax-async-callback-promise-e98f8074ebd7
function makeAjaxCall(url, methodType)
{
var promiseObj = new Promise(function(resolve, reject)
{
var xhr = new XMLHttpRequest();
xhr.open(methodType, url, true);
xhr.send();
xhr.onreadystatechange = function()
{
if (xhr.readyState === 4)
{
if (xhr.status === 200)
{
console.log("xhr done successfully");
var resp = xhr.responseText;
var respJson = JSON.parse(resp);
resolve(respJson);
}
else
{
reject(xhr.status);
console.log("xhr failed");
}
}
else {console.log('xhr processing going on');}
}
console.log("request sent succesfully");
});
return promiseObj;
}
enter code here
document.getElementById('userDetails').addEventListener('click', function()
{
// git hub url to get btford details
var userId = document.getElementById("userId").value;
var URL = "https://api.github.com/users/"+userId;
makeAjaxCall(URL, "GET").then(processUserDetailsResponse, errorHandler);
});
You can even send it the callback method. I also send it a method to use for errors.
function makeAjaxCall(url, methodType, callback)
{
$.ajax(
{
url : url,
method : methodType,
dataType : "json",
success : callback,
error : function (reason, xhr){
console.log("error in processing your request", reason);
}
});
}
// git hub url to get btford details
var URL = "https://api.github.com/users/btford";
makeAjaxCall(URL, "GET", function(respJson)
{
document.getElementById("userid").innerHTML = respJson.login;
document.getElementById("name").innerHTML = respJson.name;
document.getElementById("company").innerHTML = respJson.company;
document.getElementById("blog").innerHTML = respJson.blog;
document.getElementById("location").innerHTML = respJson.location;
});

Fake the response of a blocked XMLHttpRequest

I am intercepting an XMLHttpRequest and preventing it from making a network call.
There are third-party scripts that I want to prevent from performing retries when the XHR doesn't respond, and therefore I'd like to mimic a response with an OK status (i.e. readyState = 4). Is there a way to make this happen?
(function(XHR) {
var open = XHR.prototype.open;
var send = XHR.prototype.send;
var abort = XHR.prototype.abort;
XHR.prototype.open = function(method, url, async, user, pass) {
this._url = url;
open.call(this, method, url, async, user, pass);
};
XHR.prototype.send = function(data) {
var url = this._url;
try {
var canSend = checkCanSend(url);
if (!canSend) {
// TODO respond with OK status
this.abort();
} else {
send.call(this, data);
}
} catch (err) {
console.error(err);
}
}
XHR.prototype.abort = function() {
console.log('aborted ' + this._url);
abort.call(this);
}
})(XMLHttpRequest);

What is the vanilla JS version of Jquery's $.getJSON

I need to build a project to get into a JS bootcamp I am applying for. They tell me I may only use vanilla JS, specifically that frameworks and Jquery are not permitted. Up to this point when I wanted to retrieve a JSON file from an api I would say
$.getJSON(url, functionToPassJsonFileTo)
for JSON calls and
$.getJSON(url + "&callback?", functionToPassJsonPFileTo)
for JSONP calls. I just started programming this month so please bear in mind I don't know the difference between JSON or JSONP or how they relate to this thing called ajax. Please explain how I would get what the 2 lines above achieve in Vanilla Javascript. Thank you.
So to clarify,
function jsonp(uri){
return new Promise(function(resolve, reject){
var id = '_' + Math.round(10000 * Math.random())
var callbackName = 'jsonp_callback_' + id
window[callbackName] = function(data){
delete window[callbackName]
var ele = document.getElementById(id)
ele.parentNode.removeChild(ele)
resolve(data)
}
var src = uri + '&callback=' + callbackName
var script = document.createElement('script')
script.src = src
script.id = id
script.addEventListener('error', reject)
(document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
})
}
would be the JSONP equivalent?
Here is the Vanilla JS version for $.getJSON :
var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Ref: http://youmightnotneedjquery.com/
For JSONP SO already has the answer here
With $.getJSON you can load JSON-encoded data from the server using
a GET HTTP request.
ES6 has Fetch API which provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.
It is easier than XMLHttpRequest.
fetch(url) // Call the fetch function passing the url of the API as a parameter
.then(res => res.json())
.then(function (res) {
console.log(res)
// Your code for handling the data you get from the API
})
.catch(function() {
// This is where you run code if the server returns any errors
});
Here is a vanilla JS version of Ajax
var $ajax = (function(){
var that = {};
that.send = function(url, options) {
var on_success = options.onSuccess || function(){},
on_error = options.onError || function(){},
on_timeout = options.onTimeout || function(){},
timeout = options.timeout || 10000; // ms
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//console.log('responseText:' + xmlhttp.responseText);
try {
var data = JSON.parse(xmlhttp.responseText);
} catch(err) {
console.log(err.message + " in " + xmlhttp.responseText);
return;
}
on_success(data);
}else{
if(xmlhttp.readyState == 4){
on_error();
}
}
};
xmlhttp.timeout = timeout;
xmlhttp.ontimeout = function () {
on_timeout();
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
return that;
})();
Example:
$ajax.send("someUrl.com", {
onSuccess: function(data){
console.log("success",data);
},
onError: function(){
console.log("Error");
},
onTimeout: function(){
console.log("Timeout");
},
timeout: 10000
});
I appreciate the vanilla js equivalent of a $.getJSON above
but I come to exactly the same point. I actually was trying of getting rid of jquery which I do not master in any way .
What I'm finally strugglin with in BOTH cases is the async nature of the JSON request.
What I'm trying to achieve is to extract a variable from the async call
function shorten(url){
var request = new XMLHttpRequest();
bitly="http://api.bitly.com/v3/shorten?&apiKey=mykey&login=mylogin&longURL=";
request.open('GET', bitly+url, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
var data = JSON.parse(request.responseText).data.url;
alert ("1:"+data); //alerts fine from within
// return data is helpless
}
};
request.onerror = function() {
// There was a connection error of some sort
return url;
};
request.send();
}
now that the function is defined & works a treat
shorten("anyvalidURL"); // alerts fine from within "1: [bit.ly url]"
but how do I assign the data value (from async call) to be able to use it in my javascript after the function was called
like e.g
document.write("My tiny is : "+data);

Ajax, why the setInterval function doesn't work?

I just have a json page in localhost and I save the data of this page in a file , I need to save this page every 5 seconds, so I developed this code in ajax , using a page in php with an exec command,I used a setinterval function for the update but my code execute the function getRequest only one time.
Here the html:
<script type="text/javascript">
// handles the click event for link 1, sends the query
function getOutput() {
setInterval(function(){
getRequest(
'prova1.php', // URL for the PHP file
drawOutput, // handle successful request
drawError // handle error
);
return false;
},3000);
}
// handles drawing an error message
function drawError() {
var container = document.getElementById('output');
container.innerHTML = 'Bummer: there was an error!';
}
// handles the response, adds the html
function drawOutput(responseText) {
var container = document.getElementById('output');
container.innerHTML = responseText;
}
// helper function for cross-browser request object
function getRequest(url, success, error) {
var req = false;
try{
// most browsers
req = new XMLHttpRequest();
} catch (e){
// IE
try{
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
// try an older version
try{
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return false;
}
}
}
if (!req) return false;
if (typeof success != 'function') success = function () {};
if (typeof error!= 'function') error = function () {};
req.onreadystatechange = function(){
if(req.readyState == 4) {
return req.status === 200 ?
success(req.responseText) : error(req.status);
}
}
req.open("GET", url, true);
req.send(null);
return req;
}
</script>
And here the php page:
<?php
exec(" wget http://127.0.0.1:8082/Canvases/Fe0_Cbc1_Calibration/root.json -O provami3.json", $output);
echo 'ok';
?>
I'm new to php , javascript ajax etc and I-m learning it a piece at time, I know that maybe there is an easy way for it using jQuery but for now I'm learning Ajax, so I'd like have an advice for doing it with Ajax.
Thank you all.
Do you have called getOutput() function?I don't see it...
Working example with your code here: http://jsfiddle.net/v9xf1jsw/2/
I've only added this at the end:
getOutput();
Edit:
Working example with getOutput call into a link: http://jsfiddle.net/v9xf1jsw/8/
The JS is fine, see example here counting the loops https://jsfiddle.net/tk9kfdna/1/
<div id="output"></div>
<div id="log"></div>
<script type="text/javascript">
// handles the click event for link 1, sends the query
var times=0;
function getOutput() {
setInterval(function(){
getRequest(
'prova1.php', // URL for the PHP file
drawOutput, // handle successful request
drawError // handle error
);
return false;
},3000);
}
// handles drawing an error message
function drawError() {
var container = document.getElementById('output');
container.innerHTML = 'Bummer: there was an error!';
}
// handles the response, adds the html
function drawOutput(responseText) {
var container = document.getElementById('output');
container.innerHTML = responseText;
}
function getRequest(url, success, error) {
times++;
var req = false;
try{
// most browsers
req = new XMLHttpRequest();
} catch (e){
// IE
try{
req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
// try an older version
try{
req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return false;
}
}
}
if (!req) return false;
if (typeof success != 'function') success = function () {};
if (typeof error!= 'function') error = function () {};
req.onreadystatechange = function(){
if(req.readyState == 4) {
return req.status === 200 ?
success(req.responseText) : error(req.status);
}
}
req.open("GET", url, true);
req.send(null);
var log = document.getElementById('log');
log.innerHTML = 'Loop:'+times;
return req;
}
getOutput();
</script>
Assuming here your calling getOutput() somewhere as that was not included in your original question if not it may just be that. Otherwise what may be happening is a response from prova1.php is never being received and so the script appears like it's not working. The default timeout for XMLHttpRequest request is 0 meaning it will run forever unless you specify the timeout.
Try setting a shorter timeout by adding
req.timeout = 2000; // two seconds
Likely there is an issue with prova1.php? does prova1.php run ok when your try it standalone.
1) Return false at the end of the setInterval method, I don't believe this is necessary.
2) Use a global variable to store the setInterval, (this will also give you the option to cancel the setInterval).
var myInterval;
function getOutput() {
myInterval = setInterval(function(){
getRequest(
'prova1.php', // URL for the PHP file
drawOutput, // handle successful request
drawError // handle error
);
},3000);
}

Ajax call issues more callbacks than expected

I have this code to make an ajax request, but according to Chrome Inspector the callback associated with the request is being called twice (by this I mean the response is being logged into the console twice), 2 more logs are being printed without any content. Here's the code:
var ajax = {
pull: function (settings) {
settings.type = 'get';
settings.callback = typeof (settings.callback) === 'function' ? settings.callback : false;
settings.data = settings.data ? settings.data : null;
return this.request(settings.url, settings.type, settings.callback, settings.data);
},
request: function (url, type, callback, data) {
var ids = ['MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP'],
xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
for (var i = 0; i < ids.length; i++) {
try {
xhr = new ActiveXObject(ids[i]);
break;
} catch (e) {}
}
}
if (callback) {
xhr.onreadystatechange = function () {
callback(xhr);
};
}
xhr.open(type, url, true);
if (type.toUpperCase() === 'GET') {
xhr.send();
} else if (type.toUpperCase() === 'POST') {
xhr.send(data);
}
}
}
ajax.pull({
url: 'http://localhost/my/twtools/scripts/ajax.php',
callback: function (xhr) {
console.log(xhr.response);
}
});
xhr.onreadystatechange has several steps (numbered from 0 top 4 I do believe something like 0 = uninitialized, 1 = starting etc, although I can't rember the exact names of the steps anymore, a quick google should find them), and each step is calling your callback. If I remember correctly, the last stage is 4, so I do believe you need to check something like this
if (xhr.readyState == 4 && xhr.status == 200)
{
// call has finished successfully
}
inside you callback, i.e. to check that it is all finished and got a successful response
I've been spoilt by jQuery these days (so much easier to do with jQuery), been quite a while since I wrote raw ajax
You're using onreadystatechange, which gets called more than once (once each state change).
Try using
xhr.onload = function() {
callback(xhr);
};

Categories

Resources