Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

How to Extend a TextBox to use Google Maps

7 Jan 2010CPOL2 min read 40.2K   836  
How to extend a TextBox to get/set latitude and longitude with Google Maps.

Image 1

Introduction

Do you need to store latitude/longitude coordinates of an address, or show a little input to choose a point in Google Maps? Here is a little solution to this problem: extend the TextBox to interact with Google Maps!

Background

To create this simple control, you need only to know a little of C#, the MooTools JavaScript framework, and have a Google Maps key.

Using the Code

We will start with the code. First of all, you need to create an empty ASCX file with this sample code:

ASP.NET
<%@Control  Language="C#" AutoEventWireup="false"  src="gmapinput.cs"  %>

Then, create a new C# class file that extends a normal textbox (System.Web.UI.WebControls.TextBox):

C#
[DefaultProperty("Text")]
  [ToolboxData("<{0}:Input  runat=server></{0}:Input>")]
  public class GoogleMapInput : TextBox
  {
  ...
  }

Above all, we need a basic property (the Google Maps key); in this case, I presume that there is a web.config setting with this value and with this name: googleMapsKey.

C#
public string GoogleMapKey 
{ 
  get 
  { 
      object o = ViewState["GoogleMapKey"]; 
      if (o == null) {
        if(System.Configuration.ConfigurationSettings.
                 AppSettings["googleMapsKey"]!=null)
            return System.Configuration.ConfigurationSettings.
                          AppSettings["googleMapsKey"];            
        else 
            return string.Empty;
      }else return o.ToString(); 
  } 
  Set { ViewState["GoogleMapKey"] = value; } 
}

Now, we need to check some features:

  • Check for (and if not included) Mootools.js
  • Include the specific JavaScript code (the mootools class) to create the gmap input
  • Include the specific CSS stylesheet
C#
System.Web.UI.HtmlControls.HtmlHead myhead = this.Page.Header;

string embedobjecturl = 
  "/template/plugins/GoogleMapInput/GoogleMapInput.js";
string cssembedobjecturl = 
  "/template/plugins/GoogleMapInput/GoogleMapInput.css";

for (int i = 0; i < myhead.Controls.Count; i++)
{ 
  if (((LiteralControl)myhead.Controls[i]).Text.
           ToLower().IndexOf("mootools-1.2-core.js") == -1) {
  //include mootools
}

if (((LiteralControl)myhead.Controls[i]).Text.
         ToLower().IndexOf("mootools-1.2-more.js") == -1) {
//include mootools.more
}
//Include the embedObject url and css

Now, we need to override the render properties to write our textbox:

C#
protected override void Render(HtmlTextWriter writer)
{
    string thisContainer = this.ClientID + "CC";
    string valore = this.Text;
    string lat = "";
    string log = "";
    //check if the text value is a point and split into  the two part lat/lng
    if (!string.IsNullOrEmpty(valore) && valore.Trim() != "")
    {
        if (valore.IndexOf(',') != -1) {
            lat = valore.Trim().Substring(0, valore.IndexOf(','));
            log = valore.Trim().Substring(valore.IndexOf(',') + 1);
        }
    }
    //prepare the html code :
    writer.Write("<div id=\""+thisContainer+"\" >");
    writer.Write("<div class=\"ginputarea\">");
    writer.Write("<fieldset>");
    writer.Write("<legend>Localit&agrave;</legend>");
    writer.Write("<label for=\""+thisContainer+
                 "_inputAdd\">Localit&agrave;</label>");
    writer.Write("<input type=\"text\"  id=\""+
                 thisContainer+"_inputAdd\" />  ");
    writer.Write("<input type=\"button\"  id=\""+
                 thisContainer+"_btmAdd\" " + 
                 "value=\"update\"  class=\"btmgupd\" />");
    writer.Write("</fieldset>");
    writer.Write("<fieldset class=\"latlong\">");
    writer.Write("<legend>Coordinate</legend>");
    writer.Write("<label for=\""+thisContainer+
                 "_inputLA\">Lat.</label>");
    writer.Write("<input type=\"text\"  id=\""+
                 thisContainer+"_inputLA\" /> ");
    writer.Write("<label for=\""+thisContainer+
                 "_inputLO\">Long.</label>");
    writer.Write("<input type=\"text\"  id=\""+
                 thisContainer+"_inputLO\" />       ");
    writer.Write("<input type=\"button\"  id=\""+thisContainer+
                 "_btmLL\" value=\"update\" " + 
                 "class=\"btmgupd\" />    ");
    writer.Write("</fieldset>");
    writer.Write("</div>");
    writer.Write("<div class=\"gmaparea\">");
    writer.Write("<div id=\"" + thisContainer + 
                 "_maps\"  style=\"width:240px; height:135px;" + 
                 " border:1px solid #333;  \">");
    writer.Write("</div>");
    writer.Write("</div>");
    writer.Write("<input type=\"hidden\"  value=\"" + this.Text + 
                 "\" id=\"" + this.ClientID + 
                 "\"  name=\"" + this.UniqueID + "\" />");
    writer.Write("</div>");
    string gK = this.GoogleMapKey;
    string lato = "";
    //if the text value is a lat/lng value set
    //the start  value for the gmap Input
    if (lat.Trim() != "" &&  log.Trim() != "") {
        lato = ",latitude:'" + lat + 
               "',longitude:'"  +  log + "'";
    }
    // create the mootools class 
    writer.Write("<script language=\"javascript\" defer=\"defer\">\n");
    writer.Write("var " + this.ID + "imoEl = 
                 new  GoogleMapsObj('','','',{panelID:'" + 
                 thisContainer + "',   " + 
                 this.ClientID + "'" + lato + "}); \n");
    // declare a little javascript function to set the  point into the map:
    writer.Write("function mappa(puntoL,puntoG) {\n");
    writer.Write("" + this.ID + "imoEl.setLatLong(puntoL,puntoG);\n");
    writer.Write("}\n");
    writer.Write("</script>\n");
    // end
}

And at the end, we speak about the mootools class (presuming that you know the basics of the MooTools syntax, or you can check http://docs.mootools.net):

[Follows the JavaScript code for the mootools class:]

JavaScript
var GoogleMapsObj = new Class( {
    options: {
    panelID:'mioEmbeder',
    googlekey: '1',
    dataID : '',
    latitude:'',
    longitude:'',
    currentURL:''
    },

After the options declaration, we need to init the class:

JavaScript
initialize: function(address, lat, long, options) {
  this.options.panelID = options.panelID;
  this.options.googlekey = options.googlekey;
  if(options.dataID)
  this.options.dataID = options.dataID;
  if(options.latitude)
  this.options.latitude = options.latitude;
  if(options.longitude)
  this.options.longitude = options.longitude;
  //init leftArea:
  var inpAdd = $(this.options.panelID+'_inputAdd') ;
  var btmAdd = $(this.options.panelID+'_btmAdd')   ;
  var inpLA =  $(this.options.panelID+'_inputLA')  ;
  var inpLO =  $(this.options.panelID+'_inputLO')  ;
  var btmLL =  $(this.options.panelID+'_btmLL')    ;
  var mappa =  $(this.options.panelID+'_maps')     ;
  
  if(this.options.latitude!='') 
      inpLA.value = this.options.latitude;
  if(this.options.latitude!='') 
      inpLO.value = this.options.longitude;

  if(address.toString()!='') 
      inpAdd.value = address;
  if(lat.toString()!='')
      inpLA.value = lat;
  if(long.toString()!='')
      inpLO.value = long;

  var mioFF = this; 

After the set up of all DOM elements and values, we need to assign the events to the buttons:

JavaScript
if( btmAdd ) {
      btmAdd.addEvent('click',function(e) {
          evt = new Event(e);evt.stop();
          //clear one e 
          var address = $(mioFF.options.panelID+'_inputAdd');
          var _lat = '';
          if(address) _lat = address.value;
          if(_lat=='' ) return;
          mioFF.initGMaps(_lat);
      });
  }
  if( btmLL ) {
      btmLL.addEvent('click',function(e) {
          evt = new Event(e);evt.stop();
          var lat = $(mioFF.options.panelID+'_inputLA');
          var long = $(mioFF.options.panelID+'_inputLO');
          var _lat = '';
          var _long = '';
          if(lat) _lat = lat.value;
          if(long) _long = long.value;
          if(_lat=='' || _long=='') return;
          var objD = $(mioFF.options.dataID);
          if(objD) {
              objD.value = _lat + ','+_long;
          }
          mioFF.initGMaps('');
      });
  }

This is the more important call; with this function, we init Google Maps with or without the latitude/langitude or address info.

JavaScript
    this.initGMaps('');
},

This is the function that inits Google Maps:

JavaScript
initGMaps : function(address) {
  //get lat e long
  var lat = $(this.options.panelID+'_inputLA');
  var long = $(this.options.panelID+'_inputLO');
  var _lat = '';
  var _long = '';
  if(lat) _lat = lat.value;
  if(long) _long = long.value;
  var urlA = '';
  if(_lat!='') urlA+='&amp;lt=' + _lat;
  if(_long!='') urlA+='&amp;lg=' + _long;
  if(address!='') {
    urlA+='&ad='+escape(address);
  }
  if(this.options.currentURL!=urlA) {
    this.options.currentURL=urlA;
  } else return;
  var eCont = $(this.options.panelID+'_maps');
  eCont.empty();
  eCont.set('html','');
//continue..

This is my simple solution to show Google Maps: I use an iFrame to show the map, to set the passed URL or lat/lng coordinates (var: urlA), and to set the Google key:

JavaScript
if(window.ie) {
    var iframe = '<iframe  src="/template/plugins/GoogleMapInput/testg.aspx?g='+ 
                 this.options.googlekey+urlA+
                 '"  frameborder="0" allowtransparency="true"'+
                 '  height="135" width="240" scrolling="no"  ></iframe>';
         eCont.set('html',iframe);
 } else {
          var ifrm = new Element('iframe');
          ifrm.setProperties({
              id :'googleFrame',
            name: 'googleFrame',
            frameborder:'0',
            allowtransparency:'true',
            height:'135',
            width:'240',
            scrolling:'no'
        });
         ifrm.setProperty('src',
           "/template/plugins/GoogleMapInput/testg.aspx?g="+
           this.options.googlekey+urlA);
        eCont.adopt(ifrm);
  }
//and of the code block started into the previous section...
},

Here is another useful function to retrieve the value from the HTML input:

JavaScript
setLatLong : function(lat,long) {
      var _lat = $(this.options.panelID+'_inputLA');
      var _long = $(this.options.panelID+'_inputLO');
      if(_lat) _lat.value = lat;
      if(_long) _long.value = long;
      var objD = $(this.options.dataID);
      if(objD) {
          objD.value = lat + ','+long;
      }
    }
 //end of the javascript class
});
//other implementation for this class...
GoogleMapsObj.implement(new Options, new Events);

This is the C# part to read the querystring and to setup the default values:

ASP.NET
<%@ Page Language="c#" ContentType="text/html" ResponseEncoding="utf-8" %>
<script language="c#" runat="server">
    string googleKey="";
    string lat ="";
    string logi ="";
    string addr ="";
    void Page_Load(object o, EventArgs e ) {
        if(Request.Params["g"]==null) 
            googleKey = ""; 
        else 
            googleKey = Request.Params["g"].ToString();
        if(Request.Params["lt"]==null)
            lat = "37.4419"; 
        else 
            lat = Request.Params["lt"].ToString();
        if(Request.Params["lg"]==null)
            logi = "-122.1419"; 
        else 
            logi = Request.Params["lg"].ToString();
        if(Request.Params["ad"]==null) 
            addr = ""; 
        else 
            addr = HttpUtility.UrlDecode(Request.Params["ad"].ToString());
    }
</script>

This is the Google Maps JavaScript part:

JavaScript
<script src="http://www.google.com/jsapi?key=<%=googleKey%>" 
      type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
    google.load("maps", "2.x"); 
    var map = null;
    var geocoder = null;
    function load() {
        var latitude = <%=lat%>;
        var longitude = <%=logi%>;
        var address = '<%=addr%>';
        if (GBrowserIsCompatible()) {
            map = new google.maps.Map2(document.getElementById("map")); 
            if(!map) return;
            map.setCenter(new google.maps.LatLng(latitude, longitude), 13); 
            var marker = new google.maps.Marker(new GLatLng(latitude, longitude));
            map.addOverlay(marker);
            if(address!='') getLatLong(address);
        }
    }
    function getLatLong(address) { 
        //if the url passed is an address we need to geocode...
        geocoder = new google.maps.ClientGeocoder();
        if (geocoder) {
            geocoder.getLatLng(
                address,
                function(point) {
                    if (!point) {
                        alert(address + " not found");
                        window.parent.mappa('','');
                    } else {
                        map.setCenter(point, 13);
                        window.parent.mappa(point.lat(),point.lng());
                        var marker = new google.maps.Marker(point);
                        map.addOverlay(marker);
                    }
                }
            );
        }
    }
//]]>
</script>

And at the end, here is the full HTML code:

HTML
//[here the c# part]
<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        //[here the google map (javascript) part]
    </head>
    <body style=" margin:0px; padding:0px;" onLoad="load()" onUnload="GUnload()">
        <form runat="server">
            <div id="map" style="width: 240px; height: 135px;"></div>
        </form>
    </body>
</html>

Now we have all the files ready; at this point, we have:

  • GMapInput.cs
  • GMapInput.ascx
  • GMapInput.js
  • Testg.aspx
  • ..if you want GMapInput.css (to customize the control)

And you can include your new web control using a standard syntax like this:

ASP.NET
<%@ Register TagPrefix="gmap" 
   TagName="Input" Src="/controls/myown/gmapinput.ascx" %>

And, here is the HTML code:

XML
<gmap:Input id="myGmapTextBox" runat="server"/>

Image 2

Points of Interest

This web control is part of a CMS system called Joack joack logo developed by me and my team. We have a lot of useful controls developed to integrate useful APIs, for example, the open social API and the Facebook API.

History

This is the first edition of this control; I hope that you find more powerful solutions and upgrade it!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)