Click here to Skip to main content
15,885,366 members
Articles / Web Development / ASP.NET

How to Extend a TextBox to use Google Maps

Rate me:
Please Sign up or sign in to vote.
4.17/5 (6 votes)
7 Jan 2010CPOL2 min read 39.8K   832   28   4
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)


Written By
Web Developer FLT.lab
Italy Italy
Web Developer and Project Manager, founder of FLT.lab
Google Developer Certified on JsMaps Api

Comments and Discussions

 
GeneralLooks good! Pin
Sandeep Mewara28-Mar-10 2:23
mveSandeep Mewara28-Mar-10 2:23 
Good work..Thumbs Up | :thumbsup:
GeneralRe: Looks good! Pin
Francesco Lo Truglio (FLT.lab)28-Mar-10 2:45
Francesco Lo Truglio (FLT.lab)28-Mar-10 2:45 
Generalgood job Pin
Arlen Navasartian18-Jan-10 21:03
Arlen Navasartian18-Jan-10 21:03 
GeneralA sample image of this control Pin
Francesco Lo Truglio (FLT.lab)10-Jan-10 15:09
Francesco Lo Truglio (FLT.lab)10-Jan-10 15:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.