Compsoft Flexible Specialists

Compsoft plc

Compsoft Weblog Compsoft Website News Archive Privacy Policy Contact Us  

Monday, February 23, 2009

Vagaries of geocoding a postcode

Plotting 'lat lngs' on a map is a fairly straight forward task. Especially doing it on a Google map.

Using a .NET implementation of a Google map is nice and easy. Doing it with PHP and javaScript is a bit more of a work up, but perhaps more satisfying when you get dirty and use some of the natty little Google features available.

However, in the course of writing a site for a Letting agent [www.batterseaflats.com] I came across an unexpected result when geocoding via HTTP with Google.

To make the site really easy to administrate details of properties I thought it would be nice to have a field containing the property's postcode, and during the save process, geocode up the postcode to get a nice 'lat lng' to show on a map. Of course I based the expected result on the performance of locating a postcode via Google's own maps.google.co.uk interface, which is nice and accurate.

Unfortunately, I often ended up with addresses that weren't quite in the right place. Much as I like Germany, I was quite sure I shouldn't be displaying properties outside of London!

I switched to using the GClientGeocoder Google object, but it still wasn't accurate enough. (Consider having four or five properties in the same street to advertise, you really want them to be in the right place on the street).

So I thought I'd let the user geocode an address string (because flats are sometimes in blocks with a name that can cause problems trying to guess what the user has typed in), then allow them to move the point around on the map. A simple feature, which the client really liked!

Use GClientGeocoder to get location:

function locateAddress(address) {

geocoder.getLatLng(

address,

function(point) {

if (!point) {

alert(address + " not found");

} else {

showPoint(point);

}

});

}


When creating the marker on the map, enable the 'draggable' GMarker property:

var marker = new GMarker(point, { icon: iconAvailable, draggable: true, dragCrossmove: true });


and listen for the marker's 'dragend' and capture the new location:

GEvent.addListener(marker, "dragend", function(latlng) {

captureLatLng(latlng);

});


And when displaying the list of properties, go crazy by synchronising the mouse hovering on the sidebar list of entries with the markers by adding a Event Listeners for 'mouseover' and 'mouseout' switching the styles as needed:

GEvent.addDomListener(div, 'mouseover', function() {

div.className = 'sideHighlight';

marker.setImage('images/highlightHouse.png');

});

GEvent.addDomListener(div, 'mouseout', function() {

div.className = 'sideNormal';

marker.setImage('images/house.png');

});



Details of the Battersea Flats project can be found here: http://www.compsoft.co.uk/Portfolio_Battersea_Flats

Labels: , , , , , , ,

Thursday, February 12, 2009

Empty UpdatePanels add a blank line after callback in IE

We hit a bug the other day where we found that UpdatePanels misbehave somewhat in Internet Explorer.

We spotted it because we always have an area at the top of our pages for displaying error messages. (You can see an example of this if you go to our Contact Us page and click "Send Message" without filling in your contact details.)

If you did a callback to the page that didn't result in any errors, the UpdatePanel around the error box would remain empty. Thus in most browsers you wouldn't see anything happen at the top of the page.

However, IE would insert a blank line where the UpdatePanel was, bumping the rest of the page content down by 12 pixels or so.

This is supremely annoying as it can really throw out the design of your site. It turns out it happens even if there elements in the UpdatePanel, if they're elements that don't render anything visible on the page (empty spans, hidden input controls, etc.).

Now, one way to fix it is to set the RenderMode of the UpdatePanel to Inline. This stops the bug in IE, but it also makes the UpdatePanel render as a span instead of a div. This is no good for us because the error box (when it renders) is a div, and nesting a div inside a span is invalid html.

So here's the solution we came up with - I hope it's useful to you too!

We created a class that inherits from UpdatePanel, but overrides how it renders, adding a style of display:inline if it's rendering as a div. So now it's still a div (and so it's valid to nest div within it), but it renders inline as a span would, thus sidestepping the IE bug.

Also, as it inherits directly from UpdatePanel, we can use <Compsoft:UpdatePanel> everywhere that we'd use <asp:UpdatePanel>. It's fire-and-forget: it behaves exactly like an UpdatePanel, except without the problems.

public class UpdatePanel : UpdatePanel
{
  protected override void RenderChildren(HtmlTextWriter writer)
  {
    // IsInPartialRendering is a reliable way of
    // telling it's a callback
    if (!this.IsInPartialRendering &&
      this.RenderMode == UpdatePanelRenderMode.Block)
    {
      StringBuilder sb = new StringBuilder();
      base.RenderChildren(new HtmlTextWriter(
        new StringWriter(sb)));

      string renderedHtml = sb.ToString();

      if (!renderedHtml.StartsWith("<div "))
        // This should never happen; better safe than sorry
        throw new Exception(
          "An UpdatePanel with a RenderMode of Block "
          + "isn't rendering as a <div>");

        writer.Write("<div style=\"display:inline\"");
        writer.Write(renderedHtml.Substring(4));
    }
    else
      base.RenderChildren(writer);
  }
}

Labels: , , , , , , , ,