Search code examples
javascriptgoogle-mapsgoogle-maps-api-3autocompletegoogle-places-api

Google Places Autocomplete SearchBox: How to control (enable/disable) predictions


Is it possible to control (enable/disable) Google Places Autocomplete SearchBox (google.maps.places.SearchBox) service predictions?

Or in other words: is it possible to temporarily detach HTML input element from Autocomplete SearchBox service and then reattach it?

The thing is that I display service results just bellow HTML input element attached to SearchBox service. Problem is that after results are displayed and user focuses back on the input element, predictions are displayed over results and obscure their view. I would like to disable predictions until text in input element is changed by the user.

enter image description here

EDIT 26/Aug/2016:

Disable predictions is currently not supported by the Javascript API. Therefore I have just opened a feature request on Google. If you are interested in the feature please vote for it: Autocomplete SearchBox - Control (enable/disable) predictions..

EDIT 07/Sep/2016 - bounty award update:

Thanks to all of you who participated in answering and also in promoting the question.

Primary objective of the award was to find solution using currently available means. I am afraid this did not happen so I decided not to award the bounty.

Although none of answers bellow provides a solution, each provides some sort of lead, so thank you! Maybe those leads will point to a solution in future.

Secondary objective of the award (although not communicated directly) was to promote Autocomplete SearchBox - Control (enable/disable) predictions feature request. Its status changed to NeatIdea and has been assigned internal tracking number. It is a good sign.


Solution

  • My solution in AngularJS – it is extract from a directive.

    .pac-contained is created after instance of an Autocomplete service is created, e.g.: new google.maps.places.Autocomplete(…) or new google.maps.places.SearchBox(…).

    What I do is to find just created .pac-container in the document, store its reference and mark that container as already processes (by adding an arbitrary class .predictions-control on it). "Marking" the container is needed only when more than one .pac-container is expected to be present in application.

    Now with the reference I can control visibility (hide or show) of the .pac-contained with predictions.

    // Container element with predictions.
    var pacContainer = null;
    
    /***
     * Find predictions container without predictions-control class set.
     * Then set  predictions-control class to it and convert it into
     * Angular's jqLite object.
     * @return {jqLite object} - container or null when not found.
     */
    function getPredictionsContainer() {
        // Get div.pac-container without predictions-control class.
        var e = document.querySelector('div.pac-container:not(.predictions-control)');
        if (e){
            var container = angular.element(e);
            container.addClass('predictions-control');
            console.log('predictions-control: Container found.');
            return container;
        } else {
            console.warn('predictions-control: Container not found!');
        }
        return null;
    } // getPredictionsContainer
    
    /***
     * Loop in 50ms intervals until container is found.
     */
    function untilContainerFound(){
        pacContainer = getPredictionsContainer();
        if (pacContainer == null){
            $timeout(untilContainerFound, 50);
        }
    } // untilContainerFound
    
    this.init = function() {
        untilContainerFound();
    }; // this.init
    
    /***
     * Prevent predictions to be displayed when user clicks on the
     * input element. It is achieved by adding ng-hide CSS class to
     * predictions container. Predictions container is identified by
     * ".pac-container" CSS class selector.
     */
    this.hidePredictions = function() {
        // If predictions container was not found at directive
        // initialization try to find it now.
        if (pacContainer === null){
            pacContainer = getPredictionsContainer();
        }
        if (pacContainer){
            console.log('predictions-control: Hiding predictions.');
            pacContainer.addClass('ng-hide');
        } else {
            console.warn('predictions-control: Container not found!');
        }
    }; // this.hidePredictions
    
    /***
     * Show predictions again by removing ng-hide CSS class from
     * predictions container.
     */
    this.showPredictions = function() {
        console.log('predictions-control: Showing predictions.');
        if (pacContainer){
            pacContainer.removeClass('ng-hide');
        }
    }; // this.showPredictions
    

    Call init() right after service instance is created:

    // Create SearchBox service for auto completing search terms.
    autocomplete = new google.maps.places.SearchBox( inputElem[0] );
    // OR
    // autocomplete = new google.maps.places.Autocomplete( ..... );
    autocomplete .addListener('places_changed', callback);
    
    predictionsCtrl.init();
    

    Note: As long as it is guaranteed that two Autocomplete services are not created at the same time (e.g.: each service is on different tab) or can wait with creation of next service until .pac-container for previous service is found, it reliably works even with multiple instances of Autocomplete service.