<br><br><div class="gmail_quote">2009/4/10 James Coglan <span dir="ltr"><<a href="mailto:jcoglan@googlemail.com">jcoglan@googlemail.com</a>></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br><br><div class="gmail_quote">2009/4/10 Dan Webb <span dir="ltr"><<a href="mailto:dan@danwebb.net" target="_blank">dan@danwebb.net</a>></span><div class="im"><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<div>On Fri, Apr 10, 2009 at 11:58 AM, Andrew Stewart<br>
<<a href="mailto:boss@airbladesoftware.com" target="_blank">boss@airbladesoftware.com</a>> wrote:<br>
>> An alternative would be to replace the submit button with an <input<br>
>> type="button"> so that the submission is entirely under your control. If you<br>
>> don't have to worry about non-JS fallback (which it sounds like is a<br>
>> non-problem) that should be worth a try.<br>
<br>
</div>That's not a good solution.  Aside from the form not being submittable<br>
without JS, there are other problems associated.  Your forms won't<br>
submit when you press return as many users expect.  Don't ever change<br>
the mark up from what it should be just because you want to get a<br>
particular effect with JavaScript.  Especially in this case where<br>
there is no need at all.<br>
<br>
A possible more solid way of architecting something like this is to<br>
have the gecoding service go through your application and you get the<br>
result via Ajax.  Then if the form is submitted without that field<br>
being gecoded then your application can do the geocoding...then you<br>
get your non-JS fallback for free.</blockquote></div><div><br><br>You'd just need your geocoding function to take a callback to indicate what to do next. Some "pseudocode" (this is real code but uses a library that's not well-known -- you'll need to translate this to Prototype, jQuery, or whatever you're using):<br>

<br><span style="font-family: courier new,monospace;">// I'm assuming you have some Ajax backend that returns JSON.</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">// You'll need to modify this to call Google or whatever</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">var geocode = function(addr, callback) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    $.HTTP.GET('/geocode', {address: addr}, function(response) {</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">        callback(response.parseJSON());</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    });</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">};</span></div></div><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">var form    = $('#myForm'),</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">
    address = form.descendants('[name=address]'),</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
    lat     = form.descendants('[name=lat]'),</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
    lng     = form.descendants('[name=lng]'); </span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
var updateLatLng = function(callback) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
    geocode(address.node.value, function(data) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
        lat.set({value: data.lat});</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
        lng.set({value: data.lng});</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">        if (typeof callback == 'function') callback();</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">    });</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
};</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">address.on('blur', updateLatLng);</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">form.on('submit', function(form, evnt) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">    evnt.stopDefault();</span><br style="font-family: courier new,monospace;">

<span style="font-family: courier new,monospace;">    updateLatLng(function() { form.node.submit() });</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">});</span><br>

<br><br>Hope that's of some use.</blockquote><div><br><br>Just realised I mis-read what Dan was saying, that the action that processes the form submission on the server side should call the geocoder if necessary before saving the record. Matter of fact, this might be a better way to go if you can do it on the server, you should only be using JS if you need some UI feedback for the geocoding. What I often do is put together a Google Maps widget that lets people search for an address and drag a marker around, and this saves the current marker position into some hidden form fields -- then the user gets accurate control of location data.<br>
</div></div><br>Still, the above code shows a useful technique known as 'continuation passing style', where instead of returning a value directly, each function takes a callback to call with the data when it becomes available. It's really useful for combining async functions without tightly coupling/duplicating bits of code.<br>
<br>