Hi all,
I am usually a Perl programmer, I have some background in javascript and am attempting to create a Googleish selector div.

Please bear with me, excuse the long introduction...

Here's the details:
Our site filters content by location. I use zip codes to find radius's. So if a user wants to see content from a location that they don't know the zip code for, I have set up this neat little input field that allows you to type the zipcode OR city name.
Once you start typing a city name it queries a database for all cities that "start" with the letters you have entered. Everything worked FINE, but I was noticing a delay due to all the repeated request to my cgi script. (I'm using the onkeyup event to trigger the ajax request.)

SO!!

I had this brite idea to query the database only once on the first letter entered, have the Perl script return a JSON object and use javascript to do the further filtering (On subsequent keyup events)
Only making one AJAX request, and using the data returned from that for further narrowing of result. If the user backspaces to where the input field is empty, then I set an arbitary variable to 'empty' and upon the next letter entered a new AJAX request will be made with the new "first" letter.

So my problem...

How do I iterate over the JSON object returned?

Here is my code so far:

// AJAX CODE //
// !!!!!!!!!

var response = 'empty'; // my arbitrary var that decides weather to AJAX or not.

 
// My AJAX request function...
function makeRequest(url) {
        var httpRequest;

        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            httpRequest = new XMLHttpRequest();
            if (httpRequest.overrideMimeType) {
                httpRequest.overrideMimeType('text/xml');
                // See note below about this line
            }
        }
        else if (window.ActiveXObject) { // IE
            try {
                httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
                }
                catch (e) {
                           try {
                                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
                               }
                             catch (e) {}
                          }
                                       }

        if (!httpRequest) {
            alert('Giving up :( Cannot create an XMLHTTP instance');
            return false;
        }
        httpRequest.onreadystatechange = function() { response = httpRequest.responseText;

// Here I set the global var response to the JSON object
// and call the function that updates the div on the page. "updateAjax()"
                                                      updateAjax();
                                                        };
        httpRequest.open('GET', url, true);
        httpRequest.send('');

    }

// THIS is the function that get's called each time a user types a letter...
    function assembleRequest(b) {
// First make hidden "result" div visible...(cross browser)
    if(document.getElementById){
            document.getElementById('result').style.visibility='visible';
            }
            else if(document.all && !document.getElementById){
            document.all.result.style.visibility='visible';
            }
// Find out if they have cleared the input field...
    if(b.value){
        if(response == 'empty'){ // If so make new AJAX request...
        makeRequest('ajax/cityAjax.cgi?city='+b.value);        
        }
// If not just filter through what we already have...
        else{
        updateAjax(b);
        }
    }
// If they have cleared the field set flag to ensure new AJAX request on next letter entered.
    else{
    response = 'empty';
    }
    }
    
    
    
//  THIS is where the problem is... I need to iterate over the JSON object
// and use regexe to see if the "city name" field matches...

    function updateAjax(b){
        
        var inputText = b.value;
        var responseText = '<select name="cities" size="5" onChange="inputCity(this.form)">';
        
        var testObj = eval('( '+response+' )');
        
        for(x=0; x< testObj.results.length; x++){

// Need to set up some kinda regexe here to filter null entries based on second letter of b.value...

            responseText += "<option value='"+testObj.results[x].zip+"'>"+testObj.results[x].city+", "+testObj.results[x].state+"</option>";     
        }
        
        responseText += '</select>';
        
        document.getElementById("result").innerHTML = responseText;

        
    }

        
        
        
        document.getElementById("result").innerHTML = responseText;

        
    }



// This function just updates the input field to the correct zip, for submitting the form...
    function inputCity(e){

    var it = e.cities.options[e.cities.selectedIndex].value;

    if (it != ""){
    	    if(document.getElementById){
            document.getElementById('zipcode').value = it;
            document.getElementById('result').style.visibility='hidden';
            document.getElementById('result').blur();
            }
            else if(document.all && !document.getElementById){
            document.searchZip.zipcode.value = it;
            document.all.result.style.visibility='hidden';
            document.all.result.blur();
            }

    }
    else{
    alert('Error completing request');
   }
}

// END AJAX
//
//

The JSON object returned from my Perl script is in this format:

$json = {
"results" :
[
{ "zip" : "27603", "city" : "Raleigh", "state" : "NC"},
{ "zip" : "25071", "city" : "Elkview", "state" : "WV"},
]
};


How can I see if it matches the text entered by the user???

Any help would be greatly appreciated!!!

I had it working perfectly (albeit slowly and erratically) before I tried to use the JSON, and reponse flag var.

Thanks!

The given JSON can be simplified as:

var json = [
  {"zip" : "27603", "city" : "Raleigh", "state" : "NC"},
  {"zip" : "25071", "city" : "Elkview", "state" : "WV"}
];
for(var i = json.length - 1; i >= 0; --i) {
  var o = json[i];
  var zip = o.zip;
  var city = o.city;
  var state = o.state;
  alert(zip + " " + city + " " + state);  
}

If using your original JSON representation:

var json = {"results": [
  { "zip" : "27603", "city" : "Raleigh", "state" : "NC"},
  { "zip" : "25071", "city" : "Elkview", "state" : "WV"},
  ]
};
var arr = json.results;
if(!arr) return;
for(var i = arr.length - 1; i >= 0; --i) {
  var o = arr[i];
  var zip = o.zip;
  var city = o.city;
  var state = o.state;
  alert(zip + " " + city + " " + state);  
}

You can wrap this entire thing in a function which will analyze the JSON string fetched, iterate over all the city names and execute a given logic accordingly.
To verify the validity of your JSON, use JSONLint.

Also, I would recommend using the parseJSON method found in json.js, instead of eval .

on line 34 of the code you posted you are NOT checking to see if the request has completed. The iteration portion of the code you posted looks right, but when you make an ajax request, the onreadystatechange fires multiple times. You need to call your update function only when the request has completed. Try changing line 34 to:

httpRequest.onreadystatechange = function() {  if(httpRequest.readyState !=4)return; response = httpRequest.responseText;

if the problem persists, try alerting the length of your json array right after you execute your eval to verify that the string you are returning from your ajax request was actually converted to an object:

var testObj = eval('( '+response+' )');
alert(testObj.results.length);

Edited 3 Years Ago by Reverend Jim: Fixed formatting

another problem you are likely to encounter is that on line 38:

updateAjax();

you are NOT passing any parameter to your function. After looking at the start of your function:

function updateAjax(b){
var inputText = b.value;
...
}

your function expect an argument (most likely a reference to a form field element). Since you are currently are NOT passing any arguments, b is undefined. Hence:

var inputText = b.value;

should give you an error as soon as the request completes.

This question has already been answered. Start a new discussion instead.