Pergunta

I use an MVC template to allow the user to add multiple addresses. They click a button and this calls my template using jquery and the form is genereated. If they want to add another location they click the button again and another form is setup and so on. This template works fine but I am having some trouble using Google Maps within these templates.

The reason for using Google Maps in this scenario is to provide a nice interface for adding a longitude and latitude for the location you are adding. I'm using class here instead of id's as there could be any number of address areas on the screen.

In my mvc template I have the following markup:

<div class="body">
           <div class="st-form-line">   
                <span class="st-labeltext">Location</span>
                <a href="#" class="GetPosition">Get Latitude &amp; Longitude positions based on above address details.</a>
                <div class="mapContainer" style="display:none;">
                    <p>If the map position is incorrect simply drag the pointer to the correct location.</p>
                    <div class="map" style="width: 450px; height: 350px;"><br/></div>
                </div>
                <div class="clear"></div>
            </div>

            <div class="st-form-line">  
                <span class="st-labeltext">@Html.LabelFor(model => model.Address.Longitude)</span>
                @Html.EditorFor(model => model.Address.Longitude)
                @Html.ValidationMessageFor(model => model.Address.Longitude)
                <div class="clear"></div>
            </div>

            <div class="st-form-line">  
                <span class="st-labeltext">@Html.LabelFor(model => model.Address.Latitude)</span>
                @Html.EditorFor(model => model.Address.Latitude)
                @Html.ValidationMessageFor(model => model.Address.Latitude)
                <div class="clear"></div>
            </div>
</div>

I have the following jquery (this is the bit that's giving me an issue):

$('a.GetPosition').live("click", function (evt) {
        evt.preventDefault();
        $(this).next().show();
        var mapElement = $(this).closest('.body').find('.map');
        var latElement = $(this).closest('.body').find('[id$=__Address_Latitude]');
        var longElement = $(this).closest('.body').find('[id$=__Address_Longitude]');
        showAddress(mapElement, latElement, longElement);
    });

    // Google Map
    var map;
    function showAddress(mapElement, latElement, longElement) {
        var myLatlng = new google.maps.LatLng(40.713956, -74.006653);

        var myOptions = {
            zoom: 8,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(mapElement, myOptions);

        var marker = new google.maps.Marker({
            draggable: true,
            position: myLatlng,
            map: map,
            title: "choose location"
        });

        google.maps.event.addListener(marker, 'click', function (event) {
            latElement.val(event.latLng.lat().toFixed(5));
            longElement.val(event.latLng.lng().toFixed(5));
        });
    }

For now I am just hard coding in the default map position of '40.713956, -74.006653' but I will change this to use a real world address once I can get the map to show correctly.

I know the issue is down to the 'mapElement' but I'm not sure what is wrong. If I comment our the showAddress function call and output some text into mapElement I can see the text so it does appear to have found the right dom loction.

Any ideas I could try here? Thanks for your help.

Thanks,

Rich

Foi útil?

Solução 3

So after doing some research it's clear that Google Maps only works if I use an element id. It does not work if I pass it a class.

To work around this issue I had to dynamically add a div with a unique id when the button to show the map is clicked on.

My HTML looks like this:

    <div class="body">
        <div class="st-form-line">  
                   <span class="st-labeltext">Location</span>
                   <a href="#" class="GetPosition">Get Latitude &amp; Longitude positions based on above address details.</a>
                   <div class="mapContainer" style="display:none;">
                   <p>If the map position is incorrect simply drag the pointer to the correct location.</p>
                   <p>@Html.LabelFor(model => model.Address.Longitude) @Html.EditorFor(model => model.Address.Longitude) @Html.LabelFor(model => model.Address.Latitude) @Html.EditorFor(model => model.Address.Latitude) <br /> 
                   @Html.ValidationMessageFor(model => model.Address.Longitude) @Html.ValidationMessageFor(model => model.Address.Latitude)</p><br />
                   <div class="clear"></div>
               </div>
         </div>
     </div>  

The JavaScript looks like this:

var i = 1;
    $('a.GetPosition').live("click", function (evt) {
        evt.preventDefault();
        // build up address string for map
        var address = //added my address textboxes here - removed for brevity;
        // find the map container and make it visible
        var mapContainer = $(this).next();
        mapContainer.show();
        // create a new map div with unique id
        var mapId = 'map' + i++;
        $("<div></div>").attr("id", mapId).attr("style", "width: 600px; height: 350px;").appendTo(mapContainer);
        // find the lat long textboxes and pass to the Google map function so we can populate with co-ordinates
        var latElement = $(this).closest('.body').find('[id$=__Address_Latitude]');
        var longElement = $(this).closest('.body').find('[id$=__Address_Longitude]');
        showAddress(mapId, address, latElement, longElement);
        // finally hide the button to avoid other map divs being generated
        $(this).hide();
    });
var map;
var marker;
function showAddress(mapId, address, latElement, longElement) {

    var map = new google.maps.Map(document.getElementById(mapId), {
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        zoom: 15
    });

    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'address': address
    },
       function (results, status) {
           if (status == google.maps.GeocoderStatus.OK) {
               marker = new google.maps.Marker({
                   draggable: true,
                   position: results[0].geometry.location,
                   map: map
               });
               map.setCenter(results[0].geometry.location);
               latElement.val(results[0].geometry.location.lat().toFixed(5));
               longElement.val(results[0].geometry.location.lng().toFixed(5));

               google.maps.event.addListener(marker, 'dragend', function (event) {
                   latElement.val(event.latLng.lat().toFixed(5));
                   longElement.val(event.latLng.lng().toFixed(5));
               });
           }
       });
}

Obviously there is still some fine tuning required with the above code as error checking needs to be added, etc but hopefully this will help some other people get started with getting Google Maps working with dynamic forms.

Outras dicas

MapController looks like this:

public ActionResult Index()
        {

            string markers = "[";
            string conString = ConfigurationManager.ConnectionStrings["PTS"].ConnectionString;
            SqlCommand cmd = new SqlCommand("SELECT * FROM Project");
            using (SqlConnection con = new SqlConnection(conString))
            {
                cmd.Connection = con;
                con.Open();
                using (SqlDataReader sdr = cmd.ExecuteReader())
                {
                    while (sdr.Read())
                    {
                        markers += "{";
                        markers += string.Format("'title': '{0}',", sdr["projecttitle"]);
                        markers += string.Format("'address': '{0}',", sdr["address"]);
                        markers += string.Format("'lat': '{0}',", sdr["latitude"]);
                        markers += string.Format("'lng': '{0}',", sdr["longitude"]);
                        markers += string.Format("'description': '{0}'", sdr["explanation"]);
                        markers += "},";
                    }
                }
                con.Close();
            }

            markers += "];";
            ViewBag.Markers = markers;
             return View();
        }

Project: your database table name | title, address, description : information you want to appear on the map

Index View looks like this:

@model PTS.Models.Project

@{

ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<html>
<head>
    <style>
        .angular-google-map-container {
            height: 300px;
            box-shadow: 2px 2px 3px 3px lightgrey;
        }

        .angular-google-map {
            width: 80%;
            height: 100%;
            margin: auto 0px;
        }
    </style>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <script src="http://code.jquery.com/jquery-1.12.2.min.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js?key=yourmapkey&libraries=places"></script>
    <style>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #map {
            height: 100%;
            width: 1500px;
        }
    </style>


    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <br /><br />


    <style>
        #content {
            border: 1px solid black;
            margin-top: 2px;
            background-image: url('/Content/images/infowindow.jpg');
            /*background: #098;*/
            color: #FFF;
            font-family: Verdana, Helvetica, sans-serif;
            font-size: 12px;
            padding: .1em 1em;
            -webkit-border-radius: 2px;
            -moz-border-radius: 2px;
            border-radius: 2px;
            text-shadow: 0 -1px #000000;
            -webkit-box-shadow: 0 0 8px #000;
            box-shadow: 0 0 8px #000;
        }
    </style>


    <script>

        var markers = @Html.Raw(ViewBag.Markers);
        function myMap() {
            var mapCanvas = document.getElementById("map");

            var mapOptions = { center: new google.maps.LatLng(markers[0].lat, markers[0].lng), zoom: 8,
                mapTypeId: google.maps.MapTypeId.ROADMAP };
            var map = new google.maps.Map(mapCanvas, mapOptions);

            for (i = 0; i < markers.length; i++) {
                var data = markers[i]
                var myLatlng = new google.maps.LatLng(data.lat, data.lng);
                var marker = new google.maps.Marker({
                    position: myLatlng,
                    map: map,
                    title: data.title
                });

                var cityCircle = new google.maps.Circle({
                    strokeColor: '#FF0000',
                    strokeOpacity: 0.8,
                    strokeWeight: 2,
                    fillColor: '#FF0000',
                    fillOpacity: 0.35,
                    map: map,
                    center: myLatlng,
                    radius: 19999.45454,
                    position: myLatlng,
                    draggable:false
                });
                 var contentString = '<div id="content">' +
                                       '<b> Project Title : </b> '  + 
         data.title+ '</div>' + '<div id="content">'+
                                       '<b> Address : </b> '  + data.address 
         + '</div>' +  '<div id="content">' + '<b> Explanation  : </b> '   + data.description + '</div>' +  '</div>' ;


                var infowindow = new google.maps.InfoWindow({
                    content: contentString
                });


                marker.infowindow = infowindow;

                marker.addListener('click', function() {
                    return this.infowindow.open(map, this);
                })


                google.maps.event.addListener(marker, 'click', function() {
                    this.infowindow.open(map, this);
                });
            }
        }


    </script>

    <div id="map" style="width: 1500px; height: 1000px"></div>
    <script src="https://maps.googleapis.com/maps/api/js?key=yourmapkey&callback=myMap"></script>


</body>
</html>

this way we can show dynamically map and use our map on our site or in other projects. hope this helps !

Example code for loading static Lat and Lng:

    var initialLocation = new google.maps.LatLng(40.713956, -74.006653);
    var zoom = 4;

        var options = {
            zoom: zoom,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(document.getElementById("map_canvas"), options);
        map.setCenter(initialLocation);
        map.setZoom(zoom);

Above example will show static map on your div "map_canvas". You can also use one more important element of Google map i.e. Geocoder: this will help you to draw address on Google map

var mygc = new google.maps.Geocoder();
mygc.geocode({ 'address': address },
    function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    initialLocation = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());

                    map.setCenter(initialLocation);
                    map.setZoom(zoom);
                }
            }
    );
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top