views:

3105

answers:

8

I want to use the google geocode via HTTP functionality to translate a city name into longitude and latitude in for my AJAX web application.

However, it appears that no callback function exists for the HTTP geocoder functionality

http://code.google.com/apis/maps/documentation/geocoding/index.html

Is that true, no callback function exists?

Because if that is true, it essentially means that the Google geocode via HTTP api is useless when used with AJAX because JavaScript will throw a crossdomain exception error.

Any ideas on how I can use the geocode via HTTP api in my AJAX web application in JavaScript?

Note: I do not want to use the full blown Google Maps API which is approx 200kb download (i.e. GClientGeocoder). I want to use the HTTP api b/c of it's super quick responsiveness and lack of needing my web users from having to download the huge full blown interactive google maps api.

E.g. http://maps.google.com/maps/geo?output=json&sensor=false&key={API_KEY}&q={CITY,STATE}&CALLBACK=????

Thanks

+3  A: 

hmm....I think you'd have to have your AJAX call back to your own server, and then call Google's Geocode from your server.

Thats how I do AJAX geocoding, it all goes through my ASP.NET code.

EDIT:

In the ASP.NET webforms environment I might implements this as a lightweight ASHX file, but for the purposes of simplicity, here's an ASPX example:

public partial class GoogleHandler : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e) {
        Response.Write(GetGoogleXML("http://pseudo_googlegeocode?parameter=" + parametersFromQuerystring);
    }
}

In the example above, the .NET page is only passing the request along.

But in a real environment, I'd rather my .NET code do more than just pass the data over. This way I can do error handling, filtering, validation, business logic, all on the server, before sending that data over to the client.

Also, this allows for greater abstraction. i.e, I might change from google to yahoo geocoding. In this way I'd only have to change my serve logic, and leave the client to just receive a generic set of coordinates/location data.

Also, using that abstraction I could actually aggregate multiple data from various geocoding data sources. Again, the server takes care of aggregating, the client just receives and displays the filtered data.

andy
Seems like a terrible waste to have to create a middleman step on your website to simply download the content and repost the result to bypass the cross domain exception. Curious if there is another way around it or an undocumentated callback routine.
I hear you Tim. I guess its just security right. You know what they say, you can't break into a house that has no doors...erm, do they say that? you know what I mean
andy
@tim: just a quick comment on what you said. If you do an AJAX call to your server, as if you were doing a call straight to Google, and then just have your sever Ping google with the past parameters, then yes, you're using a middleman, but you're not reposting or downloading any superfluous content
andy
@andy - Just to make sure I understand, what you're doing is have a ASP.NET page that simply acts as a proxy. That ASP.NET page does something like a "wget" on the geocode via HTTP and then simply "echo"s the response back. That why, JavaScript (AJAX) is able to process it b/c it's now not a crossdomain call.
correction: That way*,...
@tim: hey Tim, yeah exactly. I've edited my answer to make it clearer.
andy
A: 

Look at the Google Maps API. It has some functions with callback that uses it's geocoding service.

http://code.google.com/apis/maps/documentation/reference.html#GClientGeocoder.getLatLng

cwhite
Thanks but don't want to use the full blown Google Maps API. I want to use the HTTP geocoder.
+3  A: 

Here is an example that uses the Google Maps Geocoder. The geocoder function getLocation takes a callback function as the second argument.

function findAddress(street, city, state, zip) {
  var address = [
    street,
    city.toLowerCase(),
    state.toLowerCase(),
    zip
  ].join(', ');

  if (!geocoder) {
    geocoder = new GClientGeocoder();
  }

  if (geocoder) {
    geocoder.getLocations(
      address,
      function(result) {
        var dialog, len, point;
        if (result.Status.code != G_GEO_SUCCESS) {
          alert("Error: "+result.Status.code)
        } else {
          len = result.Placemark.length;
          if (len > 1) {
            alert("Multiple matches were found.  I'll leave it as an exercise to handle this condition");
          } else {
            point = new GLatLng(
              result.Placemark[0].Point.coordinates[1],
              result.Placemark[0].Point.coordinates[0]
            );
          }
        }
      }
    );
  }
}
Jamie
Thanks but don't want to use the full blown Google Maps API. I want to use the HTTP geocoder.
+2  A: 

As others noted, you didn't read the full page. You want what that page calls the JavaScript Client Geocode.

Here's a simplified version of a script I wrote a while back. It also uses a Google Map control, but feel free to ignore that. The delay function hack is because it seemed Google was occasionally returning null when I hit their servers too fast. I don't know if this is still an issue, so don't put it in unless you have to.

<script type="text/javascript">

    //<![CDATA[

    var freezeLocations;
    var coder;
    var map;

    function load() {
      if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(38.479395, -98.349609), 4);
        map.addControl(new GLargeMapControl());
      }

      coder = new GClientGeocoder();

      missionLocations = new Array();
      missionLocationsDelayed = new Array();
      addMissionLocation("Atlanta, Georgia", "http://improveverywhere.ning.com/group/atlanta");
      //etc.
    }

    function addMissionLocation(newLocation, url)
    {
        var successful = false;
        var counter = 0;

        while(!successful && counter < 3)
        {
            coder.getLatLng(
                newLocation,
                function(point) {
                    if (!point) {
                        //alert(newLocation + " not found");
                        successful = false;
                    } else {
                        missionLocations.push(new GMarker(point, { title:newLocation}));
                        //alert(missionLocations.length);
                        map.addOverlay(missionLocations[missionLocations.length - 1]);
                        missionLocations[missionLocations.length - 1].bindInfoWindowHtml("<a href='" + url + "'>" + newLocation + "</a>");
                        successful = true;
                    }
                }
            );

            if(!successful)
            {
                delayGeocode();
            }

            counter++;
        }
    }

    function delayGeocode()
    {
        for(var i = 0; i < 2000000; i++)
        {
        }
    }


    //]]>
    </script>
Matthew Flaschen
Thanks but don't want to use the full blown Google Maps API. I want to use the HTTP geocoder.
+1  A: 

You could use Yahoo Query language as outlined in my blog post http://jawtek.blogspot.com/2009/03/unwritten-guide-to-yahoo-query-langauge.html

You would be able to use a yql statement like:

select * from json where
  url="http://maps.google.com/maps/geo?output=json&amp;sensor=false&amp;q=Indianapolis,In"

Then you would add a script tag to your html (can be done with document.createElement('script')) with a src http://query.yahooapis.com/v1/public/yql?q={your yql here}&format=json&callback={your function here} where {your yql here} is replace with a URI Encoded version of you yql statment.

swirleydude
Wouldn't this still be a cross domain exception, which AJAX prevents?
If you were trying to use a XMLHTTPRequest then yes it would be shot down. So instead you load it as a script tag and with the callback it will call one of your functions with the results.
swirleydude
A: 

I second the suggestion to create a server-side page to access the geocoder. I am doing something similar and it works great. There's a good article about working with the geocoder in PHP here.

Also note that technically you're not permitted to use Google's geocoder unless you'll be displaying the data on a Google Map - but I don't know if they'll actually check on you.

Chris B
+1  A: 

If you have looked at the documentation and not found it and both Andrew and Mike have not said "yes", and told you how to do it, I suspect you have your answer.

lol

and lets all read the service's documentation:

10.13 hide or mask from Google the identity of your service as it uses the Service, including by failing to follow the identification conventions listed in the Maps APIs Documentation; or 10.14 violate any policies in the Maps APIs Documentation or violate Google's Software Principles (...)

Also

This service is designed for geocoding static (known) addresses using a REST interface, for placement of application content on a map. For dynamic geocoding of user-defined addresses (for example, within a user interface element), consult the documentation for the JavaScript Client Geocoder or the Maps API for Flash Client Geocoder. Geocoding is a time and resource intensive task. Whenever possible, pre-geocode known addresses (using the Geocoding Service described here or another geocoding service), and store your results in a temporary cache of your own design.

But then again you could try Google Maps API V3 Geocoder

A: 

I too encountered the challenges you described above. As you indicated, Google prevents cross-domain HTTP access to the Geocode API URL:

This does severely diminish its usefulness when using client-side scripting. The only solution I found to this challenge was to create a server-side proxy service that relays the responses from the Google Maps Geocode API to my client-side script.

I wrote an extremely long-winded blog post describing this process.

Gabe