0

I have 3 Javascript functions called from the body onload in the HTML page.

Each Javascript function is contained in it's own Javascript file. Each Javascript file corresponds to another CGI script on the server.

The bodyonload.js looks like:

function bodyOnload() {
 getElementsA();
 getElementsB();
 getElementsC();
}

Each getElements function simply calls a CGI script to get the contents for 3 different selectboxes.

The problem is that as all 3 functions are called asynchronously the select boxes are getting the wrong results. It's almost like the 3 functions are stepping on each other and putting the CGI responses in the wrong selectbox. I know the CGI responses are correct. This works fine if I serially call each function from the others. Like calling the 2nd function from the first and the 3rd function from the second. The asynchronous nature of them running at the same time seems to cause the problem.

This is the general code for each javascript file that contains the getElements functions.

function getElementsA() {
    strURL = "http://test.com/scriptA.cgi";
    var xmlHttpReq = false;
    var self = this;

    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    self.xmlHttpReq.open('POST', strURL, true);
    self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    self.xmlHttpReq.onreadystatechange = function() {
        if (self.xmlHttpReq.readyState == 4) {
            fillselectboxA(self.xmlHttpReq.responseText);
        }
    }

 self.xmlHttpReq.send();

}

function fillselectboxA(str)
 {
  document.getElementById("selectBoxA").length=0;
  var results = new Array();
  results = str.split(/\n/);
  var size = results.length;
  var select = document.getElementById("selectBoxA");
  for (x=0;x<size;x++)
   {
    var element = results[x];
    select.options.add(new Option(element, x))
   }
 } 

-------------------

function getElementsB() {
    strURL = "http://test.com/scriptB.cgi";
    var xmlHttpReq = false;
    var self = this;

    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    self.xmlHttpReq.open('POST', strURL, true);
    self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-  urlencoded');
    self.xmlHttpReq.onreadystatechange = function() {
        if (self.xmlHttpReq.readyState == 4) {
            fillselectboxB(self.xmlHttpReq.responseText);
        }
    }

 self.xmlHttpReq.send();

}

function fillselectboxB(str)
 {
  document.getElementById("selectBoxB").length=0;
  var results = new Array();
  results = str.split(/\n/);
  var size = results.length;
  var select = document.getElementById("selectBoxB");
  for (x=0;x<size;x++)
   {
    var element = results[x];
    select.options.add(new Option(element, x))
   }
 } 

------------------------

function getElementsC() {
    strURL = "http://test.com/scriptC.cgi";
    var xmlHttpReq = false;
    var self = this;

    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    self.xmlHttpReq.open('POST', strURL, true);
    self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    self.xmlHttpReq.onreadystatechange = function() {
        if (self.xmlHttpReq.readyState == 4) {
            fillselectboxC(self.xmlHttpReq.responseText);
        }
    }

 self.xmlHttpReq.send();

}

function fillselectboxC(str)
 {
  document.getElementById("selectBoxC").length=0;
  var results = new Array();
  results = str.split(/\n/);
  var size = results.length;
  var select = document.getElementById("selectBoxC");
  for (x=0;x<size;x++)
   {
    var element = results[x];
    select.options.add(new Option(element, x))
   }
 } 
user770395
  • 33
  • 6
  • Unless you have a reason (which you might), you might want your one `if` statement in the `onreadystatechange` method to be `if (self.xmlHttpReq.readyState == 4 && self.xmlHttpReq.status == 200) {`. – Ian Nov 02 '12 at 02:35
  • 1
    And does `getElementsB` call something other than `fillselectbox`? I guess would you mind posting `getElementsB` and its related Javascript? – Ian Nov 02 '12 at 02:38
  • setting length of an element doesn't make sense either `document.getElementById("divA").length=0;` – charlietfl Nov 02 '12 at 02:57

1 Answers1

0

It's almost like the 3 functions are stepping on each other

That's exactly what's happening, you're overwriting the onreadystatechange handler set on getElementsA when you call getElementsB, and then again when you call getElementsC. That's because this and self are the global object in all three functions (assuming they're all similar to getElementsA).

You can circumvent that by changing your function calls to object instantiation:

function bodyOnload() {
  new getElementsA();
  new getElementsB();
  new getElementsC();
}
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • Yup That was it. Thank you very much. Functions as Objects are a bit new to me. This makes a bunch of things a lot more clear. Thank You !!!! – user770395 Nov 02 '12 at 03:44
  • @user770395 The key is the behavior of `this`, that can have different values depending on context. See this question for more details: http://stackoverflow.com/questions/3320677/this-operator-in-javascript – bfavaretto Nov 02 '12 at 23:17