variable scoping problem

Discussion in 'JavaScript' started by Tom L, Mar 4, 2010.

  1. #1
    I'm having a problem using a variable that I thought was global in scope. The code is below, but the short of it is I'm using a .js file with my php page and within that .js file I set a variable VoteStatus. Also within the .js file I call the ajax code (processvote), which works fine and this calls the function UpdateVote, which gets a return text value. In the UpdateVote function I set the variable VoteStatus equal to the value returned from the ajax call, but when I go to inspect the value of VoteStatus in the function ShowArray, which is called after the ajax call, the VoteStatus is always equal to "ERROR".
    Two questions,
    1. I thought that if I defined a variable outside of the functions and if I did not use the var keyword before it, it would have global scope and therefore I could set the value in one function and read it in another function. If so, then why does the VoteStatus always equal "ERROR" even when the VoteStatus is set from the ajax return (alert shows the correct value returning) and how/can I access the correct value from the function ShowArray?
    2. As a side question, I set the variable VoteStatus in the function UpdateVote, because it is called from the function processvote, which is the ajax call. I assumed that the processvote function required a boolean return code, which is why I used the VoteStatus variable, but used a boolean as the return value. Am I correct in this assumption?

    Thanks,
    Tom

    var i;
    i=0;
    SubmissionArray =[];
    CurrentIndex = 0;
    MaxIndex = 5;
    SubmissionID =0;
    VoteStatus = "ERROR";

    function SkipVote()
    {
    processvote(SubmissionArray[CurrentIndex][0],"SKIP");
    ShowArray();}
    function VoteNo()
    {
    processvote(SubmissionArray[CurrentIndex][0],"NO");
    ShowArray();
    }
    function VoteYes()
    {
    processvote(SubmissionArray[CurrentIndex][0],"YES");
    ShowArray();
    }
    function VoteInappropriate()
    {
    processvote(SubmissionArray[CurrentIndex][0],"INAPPROPRIATE");
    ShowArray();
    }

    function ShowArray()
    {
    CurrentIndex++;
    if (CurrentIndex < MaxIndex)
    {
    $('#submissions').fadeOut('slow', function() {
    $('#submissions').html(SubmissionArray[CurrentIndex][2]).fadeIn('slow');
    });
    }
    else
    {
    $('#submissions').fadeOut('slow', function() {
    $('#submissions').html('Thank You For Your Submissions Today.').fadeIn('slow');
    });
    }
    switch (VoteStatus)
    {
    case "SUCCESS":
    $("div#VoteMsg").html("Thank you for submitting your vote.").fadeIn("slow").delay(5000).fadeOut("slow");
    break;
    case "DUPLICATE":
    $("div#VoteMsg").html("It appears you have already voted for this submission.").fadeIn("slow").delay(5000).fadeOut("slow");
    break;
    default:
    $("div#VoteMsg").html("It appears an error has occurred with this vote, please try again.").fadeIn("slow").delay(5000).fadeOut("slow");
    break;
    }
    }

    function GetSubmissions()
    {
    $(function()
    {
    $.ajax({
    type: "GET",
    url: "getsubs.php",
    dataType: "xml",
    success: function(xml) {
    var i;
    i=0;
    $(xml).find("message").each(function(){
    // var ID = $(this).attr("id")
    var ID = $(this).find("ID").text()
    var SubmissionDateTime = $(this).find("SubmissionDateTime").text()
    var SubmissionText = $(this).find("SubmissionText").text()
    //alert(i + " " + ID + " " + SubmissionDateTime + " " + SubmissionText);
    SubmissionArray = new Array(3);
    SubmissionArray[0] = ID;
    SubmissionArray[1]= SubmissionDateTime;
    SubmissionArray[2] = SubmissionText;
    i++;
    }); //close each(
    $('#submissions').fadeOut('slow', function() {
    $('#submissions').html(SubmissionArray[CurrentIndex][2]).fadeIn('slow');
    });
    // CurrentIndex++;
    }
    }); //close $.ajax(
    }); //close $(
    }// end function

    function processvote(SubmissionID, VoteType)
    {
    createRequest();
    var url = "getthevote.php";
    url = url + "?dummy=" + new Date().getTime() + "&votetype=" + VoteType + "&submissionid=" + SubmissionID;
    request.open("GET", url, true);
    request.onreadystatechange = updateVote;
    request.send(null);

    }// end function

    function updateVote()
    {
    var rtnValue;
    if (request.readyState == 4)
    {
    if (request.status ==200)
    {
    rtnValue = request.responseText;
    if (rtnValue.length)
    {
    VoteStatus = rtnValue;
    return true;
    }
    else
    {
    VoteStatus = "ERROR";
    return false;
    }
    }
    else
    {
    VoteStatus = "ERROR";
    return false;
    } //end else
    }
    else
    {
    VoteStatus = "ERROR";
    return false;
    } //end else
    return true;
    }//end function
     
    Tom L, Mar 4, 2010 IP
  2. dimitar christoff

    dimitar christoff Active Member

    Messages:
    882
    Likes Received:
    62
    Best Answers:
    0
    Trophy Points:
    90
    #2
    right.

    it is a global variable but the problem is something else. the A in AJAX stands for asynchronous - i.e. execution gets forked
    consider your structure for the votes:

    
    function VoteYes() {
        processvote(SubmissionArray[CurrentIndex][0], "YES");
        ShowArray();
    }
    
    Code (javascript):
    it forks the submission but without waiting for the response, it goes to ShowArray();
    by the time the ajax returns whatever it's supposed to, ShowArray has run and used the last value of the VoteStatus (ERROR).

    this is why (as you can see in the jquery code) there's an onComplete event fired (or onreadystatecange if you do it manually as well like you do). the idea is, make ShowArray run THEN as callback.

    eg. if you take function updateVote() { and redefine it as:

    
    function updateVote(callback) {
        ...
        if (typeof(callback) == "function"))
            callback();
    }
    
    // then when doing the vote function:
    function processvote(SubmissionID, VoteType, callback) {
        createRequest();
        var url = "getthevote.php";
        url = url + "?dummy=" + new Date().getTime() + "&votetype=" + VoteType + "&submissionid=" + SubmissionID;
        request.open("GET", url, true);
    
        // if callback is defined, send it, else, send false
        var callback = callback || false;
    
        request.onreadystatechange = function() {
            updateVote(callback);
        }
        request.send(null);
    
    } // end function
    
    // and finally the actual vote function:
    function VoteNo() {
        processvote(SubmissionArray[CurrentIndex][0], "NO", ShowArray);
    }
    
    Code (javascript):
    in an ideal world, revert to using the jquery $.ajax, it's much cleaner - as it stands, we're currying the callback twice
     
    dimitar christoff, Mar 5, 2010 IP