1

I have a problem I can't resolve. If I hard code the array (commented out in attached code) and ignore the ajax call the map function works. However, build the array from the ajax call and nothing happens. I think it must be the array itself but I cannot see what's wrong.

This is the server side code where I'm just adding a test table

[System.Web.Services.WebMethod]
public static string GetLocations()
{
    DataTable dtSource = new DataTable();
    dtSource.Columns.Add("address", typeof(string));
    dtSource.Rows.Add("CM0 8JH");
    dtSource.Rows.Add("SE14 5RU");

    DataTable dtLatLng = new DataTable();
    dtLatLng.Columns.Add("lat", typeof(string));
    dtLatLng.Columns.Add("lng", typeof(string));

    foreach (DataRow row in dtSource.Rows)
    {
        DataTable dtWork = GetLatLng(row[0].ToString());

        foreach (DataRow rowwork in dtWork.Rows)
        {
            dtLatLng.Rows.Add(rowwork[2], rowwork[3]);
            dtWork = null;
        }
    }
    return ConvertDataTabletoString(dtLatLng);
}

public static string ConvertDataTabletoString(System.Data.DataTable dt)
{
    System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
    Dictionary<string, object> row;
    foreach (System.Data.DataRow dr in dt.Rows)
    {
        row = new Dictionary<string, object>();
        foreach (System.Data.DataColumn col in dt.Columns)
        {
            row.Add(col.ColumnName, dr[col]);
        }
        rows.Add(row);
    }
    return serializer.Serialize(rows);
}

public static DataTable GetLatLng(string address)
{
    string url = "https://maps.googleapis.com/maps/api/geocode/xml?address=" + address + "&key=AIzaSyBWQFCssXf-cic6HMYiRncde_4r9Paq9JY";
    System.Net.WebRequest request = System.Net.WebRequest.Create(url);

    using (System.Net.WebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
    {
        using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
        {
            DataSet dsResult = new DataSet();
            dsResult.ReadXml(reader);
            DataTable dtCoordinates = new DataTable();
            dtCoordinates.Columns.AddRange(new DataColumn[4] { new DataColumn("Id", typeof(int)),
                new DataColumn("Address", typeof(string)),
                new DataColumn("Latitude",typeof(string)),
                new DataColumn("Longitude",typeof(string)) });
            foreach (DataRow row in dsResult.Tables["result"].Rows)
            {
                string geometry_id = dsResult.Tables["geometry"].Select("result_id = " + row["result_id"].ToString())[0]["geometry_id"].ToString();
                DataRow location = dsResult.Tables["location"].Select("geometry_id = " + geometry_id)[0];
                dtCoordinates.Rows.Add(row["result_id"], row["formatted_address"], location["lat"], location["lng"]);
            }
            return dtCoordinates;
        }
    }
}

here is the client side code where I alternately comment out the hard coded array and call the ajax call

<style>
    #map {
        height: 500px;
    }

    html,
    body {
        height: 100%;
        margin: 0;
        padding: 0;
    }
</style>


<script type="text/javascript">
    function initMap() {
        var locations = [];

        //var locations = [
        //    { "lat": 51.6286544, "lng": 0.8193251 },
        //    { "lat": 51.4826440, "lng": -0.0473788 }
        //]

        $.ajax({
            type: "POST",
            url: "SecretSquirrel.aspx/GetLocations",
            data: "{}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (data) {
                data = $.parseJSON(data.d);
                $.each(data, function (i, item) {
                    locations.push({
                        "lat": item.lat,
                        "lng": item.lng
                    });
                    //alert(locations[i].lng);
                });
            }
        });

        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 5,
            center: {
                lat: 51.5074,
                lng: 0.1278
            }
        });

        // Create an array of alphabetical characters used to label the markers. 
        var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

        // Add some markers to the map.
        // Note: The code uses the JavaScript Array.prototype.map() method to
        // create an array of markers based on a given "locations" array.
        // The map() method here has nothing to do with the Google Maps API.
        var markers = locations.map(function (location, i) {
            return new google.maps.Marker({
                position: location,
                label: labels[i % labels.length]
            });
        });

        // Add a marker clusterer to manage the markers.
        var markerCluster = new MarkerClusterer(map, markers, {
            imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
        });
    }
</script>

<script type="text/javascript" src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js">
</script>
<script type="text/javascript" async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBWQFCssXf-cic6HMYiRncde_4r9Paq9JY&callback=initMap">
</script>

I have searched forums so am not just putting this up without exhausting myself!!! Can anyone point out the probably stupid error????

George
  • 6,630
  • 2
  • 29
  • 36
Paul Carey
  • 11
  • 2
  • 3
    `var markers = locations.map` this will run before you have any locations due to AJAX being asynchronous. Breakpoint this line and I'm 100% sure the array will be empty. – George May 11 '17 at 12:35
  • @George - Should just make that the answer :) – tymeJV May 11 '17 at 12:37
  • you have 2 options either set async: false for ajax call or call locations,map within your success function of ajax after your .each is called, even better call a separate function on success and put your remaining code of map initialization within that – Karthik Ganesan May 11 '17 at 12:38
  • @KarthikGanesan it's never really good advice to make AJAX synchronous. – George May 11 '17 at 12:45
  • I added the trailing code into the success section and the array is populated but still no display!! – Paul Carey May 11 '17 at 12:45
  • @PaulCarey I've added a fiddle for an example, just keep `data = $.parseJSON(data.d);` in your code in the success of the ajax call. – George May 11 '17 at 12:54
  • @George, it's just an option... the best way is to call all the functionality within success callback of ajax as you have mentioned in your answer. – Karthik Ganesan May 11 '17 at 13:08
  • @KarthikGanesan it is an option, but a [really bad one](http://stackoverflow.com/questions/1478295/what-does-async-false-do-in-jquery-ajax) – George May 11 '17 at 13:10
  • @George, I know that hence suggested it as an option, not an answer http://stackoverflow.com/questions/1457690/jquery-ajax-success-anonymous-function-scope – Karthik Ganesan May 11 '17 at 13:21

1 Answers1

-1

var markers = locations.map this will run before you have any locations due to AJAX being asynchronous.

Also your lat and lng are being passed as strings and not numbers.

JSFiddle For Example

To fix it you could do something like this

function initMap() {
    var locations = [];
    $.ajax({
        type: "POST",
        url: "SecretSquirrel.aspx/GetLocations",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (data) {
            data = $.parseJSON(data.d);
            $.each(data, function (i, item) {
                locations.push({
                    "lat": Number(item.lat),
                    "lng": Number(item.lng)
                });
            });
            createMarkers(map, locations);
        }
    });

    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 5,
        center: {
            lat: 51.5074,
            lng: 0.1278
        }
    });
}

function createMarkers(map, locations) {
    // Create an array of alphabetical characters used to label the markers. 
    var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

    // Add some markers to the map.
    // Note: The code uses the JavaScript Array.prototype.map() method to
    // create an array of markers based on a given "locations" array.
    // The map() method here has nothing to do with the Google Maps API.
    var markers = locations.map(function (location, i) {
        return new google.maps.Marker({
            position: location,
            label: labels[i % labels.length]
        });
    });

    // Add a marker clusterer to manage the markers.
    var markerCluster = new MarkerClusterer(map, markers, {
        imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
    });
}

I'll leave removing the markers down to you and name things how you wish.

George
  • 6,630
  • 2
  • 29
  • 36
  • many thanks George but now I have a completely blank screen. I am not a javascript programmer so miss the nuances sometimnes. Is this all within the initMap function? – Paul Carey May 11 '17 at 13:03
  • @PaulCarey That's okay, no it's not all in the initMap function, I'll change the code for you. – George May 11 '17 at 13:04
  • George, thank you, that makes sense to me, got the map back but still not displaying any markers though. Array is populated, going to bang my head on a wall lol – Paul Carey May 11 '17 at 13:13
  • @PaulCarey in that case, there may be a problem with the data you are getting back from your service – George May 11 '17 at 13:14
  • the data from the service was the initial reason I posted as I didnt realise there were other code issues. I simply can't see anything wrong with it although there is obviously something. – Paul Carey May 11 '17 at 13:18
  • @PaulCarey maybe try one more thing for me in your `$.each` do `locations.push({"lat": Number(item.lat),"lng": Number(item.lng) });` I have a feeling google doesn't like strings as it's coords – George May 11 '17 at 13:22
  • 1
    @PaulCarey do a Console.log(data) and post the result here so we can see what is going on there – Karthik Ganesan May 11 '17 at 13:24
  • BINGO!!! I will store this one in the vault!! Many thanks indeed. The Number() did it – Paul Carey May 11 '17 at 13:25
  • @PaulCarey although that fixed it, it might be better to fix it on the server side rather than the client side, glad I could help though :) – George May 11 '17 at 13:27