How to Extend a TextBox to use get/set Latitude and Longitude

In this article you will learn how to Extend a TextBox to use get/set Latitude and Longitude


Requirements:

  • Asp.Net (preferred c#)
  • Mootools (1.2)
  • A google Map Key
  • Joack System*

*the joack system requirements is intended because this is a guide to create a simple plugin control for this cms system.

Start Now!

Create an empty Ascx File with this sample code:

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

Then create a new CS class file that extend a normal textbox (System.Web.UI.WebControls.TextBox) :

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

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

public string GoogleMapKey

       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 (and if not include) the Mootools js
  • Include the specific javascript code (mootools class) to create the gmap input
  • Include the specific css stylesheet

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:

        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 now the basics of the mootools syntax, so you can check at http://docs.mootools.net):

[follows the javascript code for the mootools class:]

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

After the options declaration we need to init the class:

            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 leftAre:
            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 event to the buttons:

            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, by this function we init the Google Map with or without the lat/lng or address info (see after)

            this.initGMaps('');
      },


This is the function that init Google Map:

            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','');


This is my simple solution to show the google map: 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:

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);
            }
      },

Other useful function to retrieve the value from the html input :

            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
            }
      }                      
 });
GoogleMapsObj.implement(new Options, new Events);


Another file is called into the js (testg.aspx) the code is very simple:

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

<%@ 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>

These one is the Google Map javascript part:

<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.disableDragging();     
             //var mioPP = GPoint(latitude,longitude);     
            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);
              //marker.openInfoWindowHtml(address);
            }
          }
        );
      }
}
//]]>
</script>

And at the end the full html Code:

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

Now we have all the file 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:

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

And into the html code:

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