Ajax Class error with accessing class variable in onreadystatechange function - javascript

I am currently writing a JavaScript Ajax class and have encountered an error. In the function processRawData() I can't seem to access the class variable xhr by using this.xhr. I get "cannot read property of readyState of undefined. I have currently fixed this problem by passing in the xhr value when setting the reference to the onreadystatechange function however that seems unneeded as I should be able to access the xhr value without doing so.
function Ajax()
{
this.xhr = this.createXmlHttpRequest();
}
Ajax.prototype.createXmlHttpRequest = function()
{
if (window.XMLHttpRequest) {
try {
return new XMLHttpRequest();
} catch (e) {
throw new Error("Couldn't create XmlHttpRequest : " + e);
}
} else {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
throw new Error("Couldn't create XmlHttpRequest : " + e);
}
}
}
Ajax.prototype.request = function(type, url, params, dataType, callback)
{
if (this.xhr.readyState === 0 || this.xhr.readyState === 4) {
var isGetWithParams = (type === "GET") ? ((params !== null) ? url + params : url) : url
this.xhr.open(type, isGetWithParams, true);
this.xhr.onreadystatechange = this.processRawData(dataType, callback);
var passInParams = (type === "GET") ? null : ((params !== null) ? params : null);
this.xhr.send(passInParams);
}
}
Ajax.prototype.processRawData = function(dataType, callback)
{
return function()
{
if (this.xhr.readyState === 4 && this.xhr.status === 200) {
switch (dataType) {
case "text":
var data = this.xhr.responseText;
break;
case "xml":
default:
var data = this.xhr.responseXML;
}
callback(data);
}
}
}

Looks like your problem might be because in processRawData() you are returning another function and referencing this.xhr.readyState, but 'this' now references the returning function and not the Ajax class. Try:
Ajax.prototype.processRawData = function(dataType, callback){
var that = this; //'that' references the current Ajax instance
return function()
{
if (that.xhr.readyState === 4 && that.xhr.status === 200) {...

Related

xmlhttprequest similar to ajax

I'm attempting to send and receive data from an input to PHP through an XHR request. I have successfully managed to create a connection to PHP without passing data as a parameter within the send method.
However, if I attempt it, I receive the error.
Here is the JavaScript (updated!):
function serialize(obj, prefix) {
var str = [],
p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
var k = prefix ? prefix + "[" + p + "]" : p,
v = obj[p];
str.push((v !== null && typeof v === "object") ?
serialize(v, k) :
encodeURIComponent(k) + "=" + encodeURIComponent(v));
}
}
return str.join("&");
}
function xhrRequest(data, method, url, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
callback(xhr.responseText);
} else {
callback(null);
console.log("XHR Request Failed");
}
}
}
xhr.open(method, url, true);
xhr.send(JSON.stringify(data));
}
// Calling xhrRequest
xhrRequest({ valueA: input.value }, "POST", "post.php", function(data){
alert(data);
});
PHP is just an echo of the value to make sure it was passed (updated!):
if(isset($_POST["value"])){
echo $_POST["value"];
} else {
echo "no value set";
}
I am aware that you can pass parameters like this "valueA=" + input.value within the send method, but it seems really unnecessary (especially if there are multiple values).
So, how would I get this to work? What are some improvements / changes I might be able? to make.
Apologies if it seems very obvious, but I learnt jQuery before vanilla JavaScript, unfortunately. So I am trying to learn the vanilla way, and am used to how jQuery works.
Thanks! :)
EDIT:
Using #adeneo's technique does in fact semi-work! However, using the updated PHP, I alwasy receive "No value set". Why is the value not passing, even when I use "valueA=" + input.value?
The problem is that onreadystatechange fires multiple times during a request, you can't just use an if/else clause as it will fire four times before the status is 4 (states 0-3).
It should look like
function xhrRequest(data, method, url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
callback(xhr.responseText);
} else {
callback("XHR Request Failed"); // the error
}
}
}
xhr.open(method, url, true);
xhr.send(JSON.stringify(data));
}
// Calling xhrRequest
xhrRequest({ valueA: input.value }, "POST", "post.php", function(data){
alert(data);
});
To properly serialize the object to www-urlencoded data, you could use this one, borrowed from here
function serialize(obj, prefix) {
var str = [],
p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
var k = prefix ? prefix + "[" + p + "]" : p,
v = obj[p];
str.push((v !== null && typeof v === "object") ?
serialize(v, k) :
encodeURIComponent(k) + "=" + encodeURIComponent(v));
}
}
return str.join("&");
}
var data = serialize({ valueA: input.value });
xhrRequest(data, "POST", "post.php" ...
etc, or even add it to the xhrRequest function for convenience.
Here is a script I wrote a long time ago:
var objXMLHttp;
try{
objXMLHttp = new XMLHttpRequest();
} catch(e){
var xmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0'
,'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0'
,'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'
,'Microsoft.XMLHTTP');
for(var i = 0; i < xmlHttpVersions.length && objXMLHttp == null; i++) {
try{
objXMLHttp = new ActiveXObject( xmlHttpVersions[i] );
} catch(e){
void(0);
}
}
}
if(objXMLHttp != undefined){
objXMLHttp.onreadystatechange = function() {
/*Your response handler here*/
}
}
To send a request to the server using either the 'POST' method or the 'GET' method:
if(strMethod == "POST"){
objXMLHttp.open(strMethod, strAddr, true);
objXMLHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
bjXMLHttp.send(strData);
} else {
objXMLHttp.open(strMethod, strAddr + strData, true);
objXMLHttp.send(null);
}
I would just write a function to convert your data object to a string formatted in the way send expects, namely "name1=value1&name2=value2".
function serialize (data) {
var result = "";
for (var key in data) {
result += (encodeURIComponent(key) + "=" + encodeURIComponent(data[key].toString()) + "&");
}
return result.substring(0, result.length - 1);
}
Then the final code becomes
function xhrRequest (data, method, url, callback) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.onreadystatechange = function () {
if (xhr.status == 200 && xhr.readyState == 4) {
callback(xhr.responseText);
} else {
callback("XHR Response Failed");
}
}
xhr.send(serialize(data));
}
It might also be good to consider XMLHttpRequest onload and onerror events as described here:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
The readyState increments as the request is made so because you throw the error whenever readyState != 4 you'll always see your callback receiving the error, even if there is no error.
Check out this reference:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState

response is null in chrome and firefox

I want to call rest services using javascript. My code is:
function CreateXMLHttpRequest() {
if (typeof XMLHttpRequest != "undefined") {
alert("1");
return new XMLHttpRequest();
}
else if (typeof ActiveXObject != "undefined") {
alert("2");
return new ActiveXObject("Microsoft.XMLHTTP");
}
else {
throw new Error("XMLHttpRequestnot supported");
}
}
function CallWebService() {
var objXMLHttpRequest = null;
objXMLHttpRequest = CreateXMLHttpRequest();
objXMLHttpRequest.open("POST", "http://localhost:2546/abc.svc/json/GetXml", true);
objXMLHttpRequest.setRequestHeader("Content-Type", "application/xml;charset=UTF-16");
var packet = '<CompanyRequest xmlns="http://schemas.datacontract.org/2004/07/abc.DomainModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><CompanyName>company</CompanyName></CompanyRequest>';
objXMLHttpRequest.send(packet);
alert(packet);
var d =(objXMLHttpRequest.responseText);
alert(d);
}
It is working fine in IE, but in Firefox and chrome the response is empty. I can't understand what is going wrong. I have been searching for this for 3 days.
Let me know if there are any errors.
Thanks in advance....
You're making async call. Try to use callback.
function CreateXMLHttpRequest() {
if (typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined") {
return new ActiveXObject("Microsoft.XMLHTTP");
} else {
throw new Error("XMLHttpRequestnot supported");
}
}
function CallWebService() {
var objXMLHttpRequest = CreateXMLHttpRequest();
objXMLHttpRequest.open("POST", "http://localhost:2546/abc.svc/json/GetXml", true);
objXMLHttpRequest.setRequestHeader("Content-Type", "text/xml");
var packet = '<CompanyRequest xmlns="http://schemas.datacontract.org/2004/07/abc.DomainModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><CompanyName>company</CompanyName></CompanyRequest>';
objXMLHttpRequest.onreadystatechange = function (){
if (objXMLHttpRequest.readyState==4 && objXMLHttpRequest.status==200) {
alert(objXMLHttpRequest.responseText);
}
}
objXMLHttpRequest.send(packet);
}
You are doing an async request.
Try doing a synchronous request like
objXMLHttpRequest.open("POST", "http://localhost:2546/abc.svc/json/GetXml", false);
Or asynchronusely
objXMLHttpRequest.onreadystatechange = function () {
if ( objXMLHttpRequest.readyState == 4 ) {
alert(req.responseText);
}
};
And set the header to:
Try this:
objXMLHttpRequest.setRequestHeader("Content-Type", "text/xml");
objXMLHttpRequest.setRequestHeader( "SOAPAction", "http://localhost:2546/abc.svc/json/GetXml" );

XMLHttpRequest and setRequestHeader in IE returns an error

I try to make Cross Domain POST requests and get back JSON encoded responses,
everything works fine except in IE 7, 8, 9.
I have try those solutions but i get this error:
Object doesn't support property or method 'setRequestHeader'
Function createXMLHTTPObject() - attempt 1
function createXMLHTTPObject() {
var xmlhttp = false;
var is_IE = window.XDomainRequest ? true : false;
if (is_IE) {
xmlhttp = new window.XDomainRequest();
} else {
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlhttp;
}
Function createXMLHTTPObject() - attempt 2
var XMLHttpFactories = [
function() { return new XMLHttpRequest() },
function() { return new ActiveXObject("Msxml2.XMLHTTP") },
function() { return new ActiveXObject("Msxml3.XMLHTTP") },
function() { return new ActiveXObject("Microsoft.XMLHTTP") }
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0; i<XMLHttpFactories.length; i++) {
try {
xmlhttp = XMLHttpFactories[i]();
}
catch(e) {
continue;
}
break;
}
return xmlhttp;
}
Function send()
Here it returns the error, at: req.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
function send(postData, callback) {
var url = 'http://domain.com/ajax-processing.php'; //url overlap
var req = createXMLHTTPObject();
if (!req) return;
var method = (postData) ? "POST" : "GET";
req.open(method, url, true);
req.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
if (postData) {
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
req.onreadystatechange = function() {
if (req.readyState != 4) return;
if (req.status != 200 && req.status != 304) {
console.log('HTTP error ' + req.status);
return;
}
callback(req);
}
if (req.readyState == 4) return;
req.send(postData);
}
Here i call the send function
var insert = 'id=1&type=insert';
CLib.send(insert, function(data) {
console.log(data);
});
Is it possible to make Cross Domain requests in IE?
How i can leave behind this part, without using any other library like jQuery?
Thanks a lot #Esailija who inform me that i can't make set request headers with the XDomainRequest.
So i tried other methods and solutions also and i finally came back with a simpler method:
changed the POST requests to GET and everything working fine after some small changes.

Memory-leak at a wrapped XMLHttpRequest function

I wrote the following :
function ao(){
this.count=0;
this.flag=0;
this.tmr=0;
var self = this;
this.make=function(){
//log("before: "+this.url+" "+this.xhr);
self.xhr = (window.XMLHttpRequest)
? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
//log("after: "+this.xhr);
}
this.request = function (method, url, sendStr, delay){
this.delay=delay;
if(delay && self.tmr==0){
self.start();
}
if(self.flag==0){
this.method = method;
this.url = url;
this.sendStr = sendStr;
self.make();
this.xhr.open(method, url, true);
this.xhr.onreadystatechange = this.stateChange;
this.xhr.onabort=this.rrr;
this.xhr.onerror=this.rrr;
this.xhr.setRequestHeader("Cache-Control","no-cache");
this.xhr.send(sendStr);
}
};
this.repeat=function(){
if(this.flag==0){
this.flag=1;
this.count++;
this.xhr.open(self.method, self.url+"?"+this.count, true);
this.xhr.onreadystatechange = this.stateChange;
this.xhr.onabort=this.rrr;
this.xhr.onerror=this.rrr;
this.xhr.setRequestHeader("Cache-Control","no-cache");
this.xhr.send(self.sendStr);
}
return 0;
}
this.stop=function(){
window.clearInterval(this.tmr);
this.tmr=0;
this.flag=0;
}
this.start =function(){
self.tmr=window.setInterval(function(){self.repeat();},self.delay);
}
this.stateChange = function(){
if (self.xhr.readyState <= 1){
return;
self.log("404 errors");
} else {
if (self.xhr.readyState == 4 && self.xhr.status == 200){
self.resp = self.xhr.responseText;
if (self.callback != null)
self.callback(self.xhr.readyState, self.xhr.status);
else {
if (self.getHTML) {
self.getHTML(self.resp);
this.xhr=null;
} else {
if (self.xhr.readyState == 4 && self.xhr.status == 200){
self.parseJSON();
self.traverse();
this.ro=null;
this.xhr=null;
}
}
}
}
}
self.flag=0;
return 0;
};
and in windows ff there is a memory leak. I spent days trying to fix it, but I'm stumped.
The following works :
var x=new ao();
ao.request("POST","/cgi-bin/sdf.cgi","text",1000)
and after every 1000 miliseconds if previous request is done, it makes new request.
Developers should also take precautions when it comes to using the
onreadystatechanged event of an XMLHttpRequest object. If the handler
is a closure that closes over a reference to the same XMLHttpRequest
object, another circular dependency can be created. This isn't
necessairly detected by the above tool because the object is not part
of the DOM.
Link

Multiple xmlhttprequest on a page

I am having an error when using new XMLHttpRequest() for the second time in JavaScript code called from textbox event on page.
My JavaScript finds suggestions for text entry from the SQL to do that I use xmlhttprequest, it does fine when it is the first time but when I keep typing in the text box I receive:
"typeerror: xmlhttprequest not a costructor"
(this error happens only in Firefox)
This is my code:
function fnNull() { };
function changeofstate(){
if (XMLHttpRequest.readyState == 4)
{
whatever ;
}
XMLHttpRequest.onreadystatechange = fnNull();
}
function whentextchange(){
var WebURL = "the url here ";
XMLHttpRequest = CreateXmlHttpObject(changeOfState);
XMLHttpRequest.open("GET", WebURL, true);
XMLHttpRequest.send(null);
XMLHttpRequestt.abort();
}
}
function CreateXmlHttpObject(handler) {
var objXmlHttpReq = null;
var Req = null;
if (navigator.userAgent.indexOf("Opera")>=0)
{
return ;
}
if (navigator.userAgent.indexOf("MSIE")>=0)
{
var strName="Msxml2.XMLHTTP";
if (navigator.appVersion.indexOf("MSIE 5.5")>=0)
{
strName="Microsoft.XMLHTTP";
}
try
{
objXmlHttpReq=new ActiveXObject(strName);
objXmlHttpReq.onreadystatechange = handler;
return objXmlHttpReq;
}
catch(e)
{
return ;
}
}
if (navigator.userAgent.indexOf("Mozilla") >= 0) {
try
{
if (Req == null) {
Req = new XMLHttpRequest();
}
Req.onload = handler;
Req.onerror = handler;
return Req;
}
catch (e) {
alert(e);
alert(Req.responseText)
alert(e);
return;
}
}
}
You should name your request object something else than XMLHttpRequest. It might override the XMLHttpRequest object in the browser. Thus giving you the error.
XMLHttpRequest = CreateXmlHttpObject(changeOfState);
Assigning XMLHttpRequest variable like this is actually using global scope. You should use var and another variable name
var req = CreateXmlHttpObject(changeOfState);
Hope this clarifies.

Categories