1

Thank you in advance for your help.

I have been trying to get an autocomplete search box setup to interact with the google AutocompleteService API using angular.

At the moment my Angular AutocompleteService is working well and retrieving an array of suggested predictions based on what is typed into the search bar.

Here is my Autocomplete Service:

  angular
    .module('LocalKnowledgeApp')
    .service('AutocompleteService', [ function() {

var self = this;
var suggestions = [];



  self.initPredict = function(searchInput) {
    var predict = new google.maps.places.AutocompleteService();
    predict.getQueryPredictions({ input: searchInput }, self.displaySuggestions);
  };

  self.displaySuggestions = function(predictions, status) {
    if (status != google.maps.places.PlacesServiceStatus.OK) {
      console.log(status);
      return;
    }
    predictions.forEach(function(prediction) {
      suggestions.push(prediction.description);
    });
  };

  self.makeSuggestions = function(){
    return suggestions.slice(0,10);
  };

That service is injected into a Controller which controls the form I am trying to connect to the autocomplete. (I've only included the function that is involved in the autocomplete bit and interacts with the AutocompleteService)

angular
    .module('LocalKnowledgeApp')
    .controller('RequestController', ['LocationService', 'MarkersService', 'AutocompleteService', '$http', '$scope',
        function(LocationService, MarkersService, AutocompleteService, $http, $scope) {

    var self = this;
    var isInfoOpen = false;
    var clickedRequest = {};
    var requestUser = {};
    var autocompleteStarted;
    self.master = {};
    var autocompleteSuggestions = [];

    // var search = autoCompleteSearch;


    self.autoCompleteSearch = function(searchInput){
        if (searchInput.length < 2) {
        self.autocompleteStarted = false;
      } else {
        AutocompleteService.initPredict(searchInput);
        self.autocompleteStarted = true;
        self.autocompleteSuggestions = AutocompleteService.makeSuggestions();
        return self.autocompleteSuggestions;
      }
    };

I am now trying to wire up to get a drop-down box on the search bar so that users can then choose from the array of suggestions that the Google Autocomplete service returns to the RequestsController.

<div id="myModal" class="modal fade" role="dialog">
  <div class="modal-dialog">
    <!-- Modal content-->
    <div class="modal-content" >
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">&times;</button>
        <h4 class="modal-title">Request a tour from a local</h4>
      </div>
      <div class="modal-body">
        <form>
          <div class="form-group">
            <label for="location">Location</label>
            <div>
            <md-autocomplete
                md-search-text-change="r.autoCompleteSearch(searchText)"
                md-input-name="request.location"
                md-selected-item="selectedItem"
                md-search-text="searchText"
                md-items="item in r.autocompleteSearch(searchText)"
                md-item-text="item.display"
                md-input-minlength="0">
              <md-item-template md-highlight-text="searchText">
                {{item.display}}
              </md-item-template>
            </div>
            </md-autocomplete>

            <aside ng-show="r.autocompleteStarted" id="autocompleteSuggestions">
              <ul ng-repeat="suggestion in r.autocompleteSuggestions track by $index"> {{suggestion}} </ul>
            <aside>
          </div>

I have injected the ngMaterial module, and have all the bower components required in the right place - I know this because the directive is responsive to input, but it only shows a grey box.

(function() {
  'use strict';

  angular
    .module('LocalKnowledgeApp', ['ngResource', 'ngMaterial']);

}());

This is what my webpage is looking like...

[Odd Grey Box[1]

Any help much appreciated!

Viola Crellin
  • 61
  • 2
  • 8

1 Answers1

1

Angular directive:

'use strict';

angular.module('locationApp', ['ngAnimate', 'ngMaterial']);
angular.module('locationApp')
.controller('HomeCtrl', function ($scope) {
    // $scope.location={};

});
/**
 * @ngdoc directive
 * @name locationApp.directive:placeAutocomplete
 * @description
 *
 * # An element directive that provides a dropdown of
 * location suggestions based on the search string.
 * When an item is selected, the location's latitude
 * and longitude are determined.
 * 
 * This directive depends on the Google Maps API
 * with the places library
 * 
 * <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
 * 
 * Usage:
 * <place-autocomplete ng-model="selectedLocation"></place-autocomplete>
 *
 * Credit:
 * http://stackoverflow.com/a/31510437/293847
 */
angular.module('locationApp')
  .directive('placeAutocomplete', function () {
      return {
          templateUrl: 'place-autocomplete.html',
          restrict: 'AEC',
          replace: true,
          scope: {
              'ngModel': '='
          },
          controller: function ($scope, $q) {
              if (!google || !google.maps) {
                  throw new Error('Google Maps JS library is not loaded!');
              } else if (!google.maps.places) {
                  throw new Error('Google Maps JS library does not have the Places module');
              }
              console.log('google.maps.places ', google.maps.places);
              var autocompleteService = new google.maps.places.AutocompleteService();
              var map = new google.maps.Map(document.createElement('div'));
              var placeService = new google.maps.places.PlacesService(map);
              console.log('google.maps.places ', placeService);
              $scope.ngModel = {};

              /**
               * @ngdoc function
               * @name getResults
               * @description
               *
               * Helper function that accepts an input string
               * and fetches the relevant location suggestions
               *
               * This wraps the Google Places Autocomplete Api
               * in a promise.
               *
               * Refer: https://developers.google.com/maps/documentation/javascript/places-autocomplete#place_autocomplete_service
               */
              var getResults = function (address) {
                  var deferred = $q.defer();
                  console.log('address ', address, autocompleteService)
                  autocompleteService.getQueryPredictions({
                      input: address,
                      component: {
                          country: 'IN'
                      }
                  }, function (data) {
                      deferred.resolve(data);
                  });
                  return deferred.promise;
              };

              /**
               * @ngdoc function
               * @name getDetails
               * @description
               * Helper function that accepts a place and fetches
               * more information about the place. This is necessary
               * to determine the latitude and longitude of the place.
               *
               * This wraps the Google Places Details Api in a promise.
               *
               * Refer: https://developers.google.com/maps/documentation/javascript/places#place_details_requests
               */
              var getDetails = function (place) {
                  var deferred = $q.defer();
                  placeService.getDetails({
                      'placeId': place.place_id
                  }, function (details) {
                      deferred.resolve(details);
                  });
                  return deferred.promise;
              };

              $scope.search = function (input) {
                  if (!input) {
                      return;
                  }
                  return getResults(input).then(function (places) {
                      return places;
                  });
              };
              /**
               * @ngdoc function
               * @name getLatLng
               * @description
               * Updates the scope ngModel variable with details of the selected place.
               * The latitude, longitude and name of the place are made available.
               *
               * This function is called every time a location is selected from among
               * the suggestions.
               */
                $scope.getLatLng = function (place) {
                if (!place) {
                    $scope.ngModel = {};
                    return;
                }
                getDetails(place).then(function (details) {
                    $scope.ngModel = {
                        'name': place.description,
                        'latitude': details.geometry.location.lat(),
                        'longitude': details.geometry.location.lng(),
                    };
                });
            }
        }
    };
});

HTML portion:

<!DOCTYPE html>
<html ng-app="locationApp">
    <head>
        <!-- <link rel="stylesheet" href="place-autocomplete.css" /> -->
        <link rel="stylesheet" href="//rawgit.com/angular/bower-material/master/angular-material.css" />

        <script data-require="angular.js@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular.js"></script>
        <!-- <script data-require="angular-route.js@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular-route.js"></script> -->
        <script data-require="angular-aria@1.4.0" data-semver="1.4.0" src="https://code.angularjs.org/1.4.0/angular-aria.js"></script>
        <script data-require="angular-animate@1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
        <script src="//rawgit.com/angular/bower-material/master/angular-material.js"></script>
        <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
        <script src="place-autocomplete.js"></script>
    </head>

    <body>
        <md-content>
            <md-toolbar>
                <div class="md-toolbar-tools">
                    <h2>
                        <span>Google places/location suggestions with md-autocomplete</span>
                    </h2>
                    <span flex></span>
                </div>
            </md-toolbar>
        </md-content>
        <md-content layout-padding>
            <p>Start typing the name of a place/location below</p>
            <div class="md-padding">
                <place-autocomplete ng-model="location"></place-autocomplete>
                <place-autocomplete ng-model="location1"></place-autocomplete>
                <place-autocomplete ng-model="location2"></place-autocomplete>
                <place-autocomplete ng-model="location3"></place-autocomplete>
                {{location}}
                {{location1}}
                {{location2}}
                {{location3}}
                <script type="text/ng-template" id="place-autocomplete.html">
                    <div>
                        <md-autocomplete md-no-cache="false" md-selected-item="location" md-selected-item-change="getLatLng(item)" ng-model-options="{debounce: 600}" md-search-text-change="search(searchText)" md-search-text="searchText" md-items="item in search(searchText)" md-item-text="item.description" md-min-length="2" md-max-length="50" md-floating-label="Location (place, city or region)">
                            <md-item-template>
                                <span md-highlight-text="searchText" md-highlight-flags="^i">{{item.description}}</span>
                            </md-item-template>
                            <md-not-found>
                                No matches found for "{{searchText.description}}".
                            </md-not-found>
                        </md-autocomplete>
                    </div>
                </script>
                <div ng-if="location.name">
                    <h4>Selected location</h4>
                    <pre>{{location}}</pre>
                </div>
            </div>
        </md-content>
    </body>
</html>

For more detail:

https://gist.github.com/vinaygopinath/49df0b58a276281e5ffa

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Arun chauhan
  • 117
  • 12