Creating Google Maps AutoComplete DropDown With Multiple Map Pointers

What do we want to achieve,

  • Create a Google Maps AutoComplete dropdown.
  • Save those address details into our database Server (here, I am using SQL Server).
  • Retrieve those map details into the browser, create and place markers on the map.
  • Navigate between markers on mouse click.
Note

Before creating the project, I will show you how to get API key for Google Maps API. 

Step 1.0

Create a Google Maps API from Google console application

It will take some time to create the project.

  • Click Google Maps Javascript API link at the right side under Google Maps APIs.

  • Click "Enable" to enable API.

  • Once you enable, you will see one button “Create Credential”.

  • Copy your credentials somewhere.

The credentials have been created. Now, create an MVC project.

Step 1.1

Create an MVC project and name it as GoogleMapTutor.

  • Go to Add > New Project > ASP.NET Web Application.

  • Select MVC with No Authentication (As we don't need authentication).

  • Right click on References and click "Manage NuGet Packages".

     

  • Add packages AngularJS.Core and Entity Framework.



Step 2

Create Place.cs and MapDbContext.cs files into "Models" folder.

  • Add the code given below inside Place.cs file.

    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.ComponentModel.DataAnnotations;  
    4. using System.Linq;  
    5. using System.Web;  
    6. namespace GoogleMapTutor.Models {  
    7.     public partial class Place {  
    8.         [Key]  
    9.         public Guid Id {  
    10.             get;  
    11.             set;  
    12.         }  
    13.         public string PlaceGroupId {  
    14.             get;  
    15.             set;  
    16.         }  
    17.         public string PlaceId {  
    18.             get;  
    19.             set;  
    20.         }  
    21.         public string FullAddress {  
    22.             get;  
    23.             set;  
    24.         }  
    25.         public string Latitude {  
    26.             get;  
    27.             set;  
    28.         }  
    29.         public string Longitude {  
    30.             get;  
    31.             set;  
    32.         }  
    33.     }  
    34. }  
  • Add the code into MapDbContext.cs file.

    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Data.Entity;  
    4. using System.Linq;  
    5. using System.Web;  
    6. namespace GoogleMapTutor.Models {  
    7.     public class MapDbContext: DbContext {  
    8.         public MapDbContext(): base("GoogleMapConnString") {  
    9.             Database.SetInitializer < MapDbContext > (new DropCreateDatabaseIfModelChanges < MapDbContext > ());  
    10.         }  
    11.         public DbSet < Place > places {  
    12.             get;  
    13.             set;  
    14.         }  
    15.     }  
    16. }  

    The  code given above is to generate a database, using Entity Framework Code-First Approach.

Step 3

Add the connection string into Web.config file.

  • Add the code given below for the database connection string. You do not have localDB installed but you can change the connection string to sqlserver db. 

    1. <connectionStrings>  
    2.     <add name="GoogleMapConnString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|Database1.mdf;Integrated Security=True" providerName="System.Data.SqlClient" />  
    3. </connectionStrings>   

Step 4

Add a Controller into Controllers > PlacesController and paste the code given below.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using GoogleMapTutor.Models;  
  7. namespace GoogleMapTutor.Controllers {  
  8.     public class PlacesController: Controller {}  
  9. }   
  • Add 4 action methods given below into the Controller class.

    1. MapDbContext db = new MapDbContext();  
    2. public ActionResult Index() {  
    3.         //var result = db.places.GroupBy(x => x.PlaceGroupId).Select(grp => grp.ToList()).ToList();    
    4.         var items = new List < SelectListItem > ();  
    5.         var groups = db.places.Select(x => new SelectListItem {  
    6.             Text = x.PlaceGroupId, Value = x.PlaceGroupId  
    7.         }).Distinct().ToList();  
    8.         if (groups != null && groups.Count > 0) {  
    9.             groups[0].Selected = true;  
    10.         }  
    11.         return View(groups);  
    12.     }  
    13.     [HttpGet]  
    14. public ActionResult Add() {  
    15.         return View();  
    16.     }  
    17.     [HttpPost]  
    18. public ActionResult Add(List < Place > places) {  
    19.         places.ForEach(x => x.Id = Guid.NewGuid());  
    20.         db.places.AddRange(places);  
    21.         var result = db.SaveChanges();  
    22.         if (result > 0) {  
    23.             return Json(new {  
    24.                 result = "Redirect", url = Url.Action("Index""Places")  
    25.             });  
    26.         }  
    27.         return Json(new {  
    28.             result = "InvalidLogin"  
    29.         }, JsonRequestBehavior.AllowGet);  
    30.     }  
    31.     [HttpGet]  
    32. public JsonResult GetLocationsByGroupId(string groupid) {  
    33.     var locations = db.places.Where(x => x.PlaceGroupId == groupid).ToList();  
    34.     return Json(locations, JsonRequestBehavior.AllowGet);  
    35. }  
  • The first is Method Index() which returns List<SelectListItem>() for dropdown. 

  • The last method is to get all the places, which are based on its GroupId. This function will return JSON data.  

Step 5

Create two files “Add.cshtml” and “Index.cshtml” into Into Views>Places folder (Create Places folder, if it does not exist).

Note

Please make sure that in Layout.cshtml page, jQuery and Bootstrap are referred.

Step 6

Open “Add.cshtml” file

  • Remove all the code from the page and paste the code given below.

  • Replace the credentials used for the Application and paste your own credentials into Google API script tag given below.

    1. @ {  
    2.     ViewBag.Title = "Add";  
    3. } < div ng - app = "googleMapApp"  
    4. ng - controller = "googleMapController"  
    5. ng - cloak id = "angular_scope" > < div style = "margin:70px 0;" > < /div>   < div class = "row"  
    6. ng - show = "IsLoaded" > < div class = "col-xs-12" > < h4 > Add Places < /h4>   < table class = "table table-bordered table-hover table-striped" > < thead > < tr > < th class = "col-sm-2" > Sl No < /th>   < th > Id < /th>   < th > Full Address < /th>   < th > Latitude < /th>   < th > Longitude < /th>   < td > Action < /td>   < /tr>   < /thead>   < tbody > < tr > < td > < /td>   < td colspan = "6" > < span google - map - directive placelist = "placeList"  
    7. groupid = "groupId" > < /span>   < /td>   < /tr>   < tr ng - repeat = "place in placeList" > < td > {  
    8.     {  
    9.         $index + 1  
    10.     }  
    11. } < /td>   < td > {  
    12.     {  
    13.         place.PlaceId  
    14.     }  
    15. } < /td>   < td > {  
    16.     {  
    17.         place.FullAddress  
    18.     }  
    19. } < /td>   < td > {  
    20.     {  
    21.         place.Latitude  
    22.     }  
    23. } < /td>   < td > {  
    24.     {  
    25.         place.Longitude  
    26.     }  
    27. } < /td>   < td > < input type = "button"  
    28. class = "btn btn-xs btn-primary"  
    29. ng - click = "remove(place)"  
    30. value = "delete" / > < /td>   < /tr>   < /tbody>   < tfoot > < tr > < td colspan = "6" > < div class = "text-right" > < input type = "text"  
    31. placeholder = "Enter Group Id"  
    32. class = "input-sm"  
    33. ng - model = "groupId" / > < input type = "button"  
    34. class = "btn btn-primary"  
    35. ng - click = "post()"  
    36. value = "Add Places" / > < /div>   < /td>   < /tr>   < /tfoot>   < /table>   < /div>   < /div>   < /div>    
    37. @section scripts { < script src = "https://maps.googleapis.com/maps/api/js?libraries=places&sensor=false&key=AIzaSyD3fJEYrzU3pvnZ_DGwBN0yxM-e7fCbNjI" > < /script>   < script src = "~/Scripts/angular.js" > < /script>   < script src = "~/Scripts/app/add.js" > < /script>    
    38. }   

Step 7

Create an app folder into Scripts folder and add add.js file.

  • Paste the code given below into add.js file.

    1. angular.module("googleMapApp", []).controller("googleMapController", ['$scope''$filter''googleMapFactory'function($scope, $filter, googleMapFactory) {  
    2.     $scope.IsLoaded = true;  
    3.     $scope.placeList = [];  
    4.     $scope.remove = function(place) {  
    5.         //var newTemp = $filter("filter")($scope.placeList, { PlaceId: place_id });    
    6.         var index = $scope.placeList.indexOf(place);  
    7.         $scope.placeList.splice(index, 1);  
    8.     }  
    9.     $scope.post = function() {  
    10.         if (!$scope.groupId) {  
    11.             alert("please add a group id.");  
    12.             return  
    13.         }  
    14.         if (!$scope.placeList.length) {  
    15.             alert("please add atleast one place.");  
    16.             return  
    17.         }  
    18.         angular.forEach($scope.placeList, function(item, index) {  
    19.             item.PlaceGroupId = $scope.groupId;  
    20.         })  
    21.         googleMapFactory.Post($scope.placeList).then(function(response) {  
    22.             if (response.data.result == "Redirect") {  
    23.                 window.location = response.data.url;  
    24.                 return  
    25.             } else {  
    26.                 alert("Failed");  
    27.             }  
    28.         }, function(error) {  
    29.             debugger  
    30.             alert("Failed");  
    31.         })  
    32.     }  
    33. }]).factory("googleMapFactory"function($http) {  
    34.     var fac = {}  
    35.     fac.Post = function(data) {  
    36.         return $http.post("/Places/Add", data)  
    37.     }  
    38.     return fac  
    39. }).directive("googleMapDirective"function() {  
    40.     return {  
    41.         restrict: 'EA',  
    42.         scope: {  
    43.             placelist: "="  
    44.         },  
    45.         template: '<div class="row"><div class="col-sm-8"><input type="text" id="input-add" ng-model="newPlace.PlaceId" class="form-control input-sm" /></div></div>',  
    46.         link: function(scope, element, attrs) {  
    47.             google.maps.event.addDomListener(window, 'load', initialize);  
    48.   
    49.             function initialize() {  
    50.                 var input = document.getElementById('input-add');  
    51.                 var autocomplete = new google.maps.places.Autocomplete(input);  
    52.                 autocomplete.addListener('place_changed'function() {  
    53.                     debugger  
    54.                     var place = autocomplete.getPlace();  
    55.                     var newPlace = {  
    56.                         PlaceId: place.place_id,  
    57.                         FullAddress: place.formatted_address,  
    58.                         Latitude: place.geometry['location'].lat(),  
    59.                         Longitude: place.geometry['location'].lng()  
    60.                     }  
    61.                     var result = $.grep(scope.placelist, function(e) {  
    62.                         return e.PlaceId == newPlace.PlaceId;  
    63.                     });  
    64.                     if (result.length == 0) {  
    65.                         scope.placelist.push(newPlace);  
    66.                     } else {  
    67.                         alert("This Place Already Added!!!")  
    68.                     }  
    69.                     input.value = '';  
    70.                     console.log($('.pac-container'));  
    71.                     $('.pac-container').html("");  
    72.                     scope.$apply();  
    73.                 });  
    74.             }  
    75.             $(element).on('click''#button-add'function(e) {  
    76.                 alert();  
    77.             });  
    78.         }  
    79.     }  
    80. })   
  • In JS given above, I have created one Controller for our View, one factory to communicate with our back-end Server, and one directive for Google Maps auto-complete.

  • The directive will simply create the auto-complete dropdown into our HTML page.  

Step 8

Run the Application

  • Go to /Places/Add and test whether it works or not.

  • Add some places, which you like.

  • Save the places.

Step 9

Index.cshtml file,

  • Remove everything and paste the code given below into index.cshtml file in Places folder.

  • Replace the credentials used for the Application and paste your own credentials into Google API script tag given below.

Step 10

Add “index.js” and “google-map-dir.js” files into Scripts>app and Scripts>app>Directives(create Directives folder, if it does not exist) folders respectively.

Step 11

Paste the code given below into index.js file.

  1. angular.module('GoogleMapApp', ['googleMapDirectiveApp']).controller('GoogleMapAppController'function($scope, GoogleMapAppFactory) {  
  2.     $scope.init = function() {  
  3.         GoogleMapAppFactory.GetLocations($scope.groupId).then(function(response) {  
  4.             $scope.locationList = response.data;  
  5.             if ($scope.locationList && $scope.locationList.length) {  
  6.                 $scope.GoToThisLocation($scope.locationList[0].Latitude, $scope.locationList[0].Longitude);  
  7.             }  
  8.         }, function(error) {  
  9.             alert("error!!!");  
  10.         })  
  11.     }  
  12.     $scope.selectedLocation = {  
  13.         lat: 23,  
  14.         lon: 79  
  15.     };  
  16.     $scope.GoToThisLocation = function(lat, lon) {  
  17.         if ($scope.selectedLocation.lat != lat || $scope.selectedLocation.lon != lon) {  
  18.             $scope.selectedLocation = {  
  19.                 lat: lat,  
  20.                 lon: lon  
  21.             };  
  22.             if (!$scope.$$phase) {  
  23.                 $scope.$apply("selectedLocation");  
  24.             }  
  25.         }  
  26.     }  
  27.     //$scope.init();    
  28. }).factory("GoogleMapAppFactory"function($http) {  
  29.     var fac = {}  
  30.     fac.GetLocations = function(locationGroupId) {  
  31.         return $http.get('/Places/GetLocationsByGroupId?groupid=' + locationGroupId)  
  32.     }  
  33.     return fac;  
  34. })   

$scope.GoToThisLocation() function will be called when we change (select) a particular place from the place list.

Step 12

Add the code given below into google-map-dir.js file.
  1. angular.module("googleMapDirectiveApp", []).directive('googleMapDir'function() {  
  2.     return {  
  3.         restrict: "EA",  
  4.         replace: true,  
  5.         template: "<div></div>",  
  6.         scope: {  
  7.             center: '=',  
  8.             markers: '=',  
  9.             width: "@",  
  10.             height: "@"  
  11.         },  
  12.         link: function(scope, element, attribute) {  
  13.             //debugger    
  14.             var map;  
  15.             scope.$watch('center'function() {  
  16.                 //debugger    
  17.                 if (map && scope.center && scope.markers) {  
  18.                     map.setCenter(getLocation(scope.center))  
  19.                 }  
  20.             })  
  21.             scope.$watch('markers'function() {  
  22.                 //debugger    
  23.                 if (scope.markers) {  
  24.                     updateControl();  
  25.                 }  
  26.             })  
  27.   
  28.             function updateControl() {  
  29.                 //debugger    
  30.                 var options = {  
  31.                     center: new google.maps.LatLng(23, 79),  
  32.                     zoom: 15,  
  33.                     mapTypeId: "roadmap"  
  34.                 }  
  35.                 if (scope.center.lat && scope.center.lon) {  
  36.                     options.center = getLocation(scope.center)  
  37.                 } else {  
  38.                     return  
  39.                 }  
  40.                 map = new google.maps.Map(element[0], options);  
  41.                 updateMarkers();  
  42.             }  
  43.   
  44.             function updateMarkers() {  
  45.                 //debugger    
  46.                 // create new markers    
  47.                 currentMarkers = [];  
  48.                 var markers = scope.markers;  
  49.                 if (angular.isString(markers)) markers = scope.$eval(scope.markers);  
  50.                 for (var i = 0; i < markers.length; i++) {  
  51.                     var m = markers[i];  
  52.                     var loc = new google.maps.LatLng(m.Latitude, m.Longitude);  
  53.                     var mm = new google.maps.Marker({  
  54.                         position: loc,  
  55.                         map: map,  
  56.                         title: m.FullAddress  
  57.                     });  
  58.                     currentMarkers.push(mm);  
  59.                 }  
  60.             }  
  61.   
  62.             function getLocation(location) {  
  63.                 if (location == null) {  
  64.                     return new google.maps.LatLng(23, 79);  
  65.                 }  
  66.                 if (angular.isString(location)) {  
  67.                     location = scope.$eval(location);  
  68.                 }  
  69.                 return new google.maps.LatLng(location.lat, location.lon)  
  70.             }  
  71.         }  
  72.     }  
  73. })  

Step 13 

Run the Application.

  • Go to /Places/Index.

  • The screen should look similar to the one shown below.

Great. You have created Google Maps auto-complete with multiple pointers with navigation.