elethan
elethan

Reputation: 16993

Different behavior when form is submitted with ENTER vs. clicking submit button

I have an HTML form input element that uses a SearchBox from the Google Maps Places API for auto-completion. In my JavaScript I have created a SearchBox instance as follows:

var input = $('#spotsearch')[0];  // Refers to a form input with type="text" in my HTML
searchBox = new google.maps.places.SearchBox(input);

Later in in my JavaScript, I have the following:

$('#searchform').submit(function () {
    var places = searchBox.getPlaces();
    if (places) {
        var spotLat = searchBox.getPlaces()[0].geometry.location.lat();
        var spotLng = searchBox.getPlaces()[0].geometry.location.lng();
        $('#latitude').val(spotLat);
        $('#longitude').val(spotLng);
    }

});

Here is my issue: after selecting a completion candidate, when I submit the form by clicking the form's submit button, everything works as expected, and places will reference an array with a single object. However, if I submit the form by pressing ENTER, the anonymous function still gets called, but places returns an empty array. In both cases, it seems that the request being sent is exactly the same. What am I missing here?

I am new to JavaScript and to the Goggle Maps API, so I am not sure where my mistake originates. My intuition is that it may be related to timing in some way, but that is really just a vague hunch. Any suggestions would be appreciated. Thank you!

Edit:

To provide a bit more detail, here is my entire script:

var searchBox;
var places;
function initSearchBox() {
    var KCLatLng = new google.maps.LatLng({lat: 39.093201, lng: -94.573419});
    var bounds = new google.maps.LatLngBounds(KCLatLng);

    var input = $('#spotsearch')[0];
    searchBox = new google.maps.places.SearchBox(input);
    searchBox.setBounds(bounds);

    $('#searchform').submit(function () {
        var places = searchBox.getPlaces();
        if (places) {
            var spotLat = searchBox.getPlaces()[0].geometry.location.lat();
            var spotLng = searchBox.getPlaces()[0].geometry.location.lng();
            $('#latitude').val(spotLat);
            $('#longitude').val(spotLng);
        }

    });
}

initSearchBox is then passed as the callback parameter when I load the Goggle Maps API.

I have also tried doing it this way:

var searchBox;
var places;
function initSearchBox() {
    var KCLatLng = new google.maps.LatLng({lat: 39.093201, lng: -94.573419});
    var bounds = new google.maps.LatLngBounds(KCLatLng);

    var input = $('#spotsearch')[0];
    searchBox = new google.maps.places.SearchBox(input);
    searchBox.setBounds(bounds);
    searchBox.addListener('places_changed', function() {
        var places = searchBox.getPlaces();
        if (places) {
            var spotLat = searchBox.getPlaces()[0].geometry.location.lat();
            var spotLng = searchBox.getPlaces()[0].geometry.location.lng();
            $('#latitude').val(spotLat);
            $('#longitude').val(spotLng);
        }
    });
}

But this gives me the same result (hitting ENTER does not set the value of #latitude or #longitude, but clicking the submit button does).

Here is the HTML of my form (using Django templates and Bootstrap):

<form method="get" id="searchform" action="{% url 'spot_search' %}"
      class="navbar-form navbar-left plain" role="search">
    <div class="form-group">
        <input id="spotsearch" type="text" class="form-control plain"
               placeholder="Search spots" name="search_query">
    </div>

    <button type="submit" class="btn btn-default plain">
        <span class="glyphicon glyphicon-search"></span> Search
    </button>
    <input id="latitude" name="latitude" type="hidden">
    <input id="longitude" name="longitude" type="hidden">
</form>

Upvotes: 0

Views: 1049

Answers (3)

elethan
elethan

Reputation: 16993

Thanks @adam0101 for pointing me to this question. I also found the related questions here, here and here to be useful. I missed them in my first pass at researching the issue, because the issue was more specific to the Google Maps autocomplete API than I had realized.

While I considered marking my question as duplicate, I have decided to instead post the solution that I ended up going with, which is heavily inspired by this highly upvoted - but not accepted - answer. I simply added the following to my existing JavaScript:

$('#spotsearch').keydown(function (e) {
    // Don't submit form unless values have been set
    var condition = $('#latitude').val() == "" && $('#longitude').val() == "";
    if (e.which == 13 && condition) {
        return false;
    }
});

This way, the first time the user presses enter on an autocompletion candidate it will select that candidate (instead of submitting the form before the candidate can be selected). Then the user can either hit enter again to submit the form, or click the Search button to do the same thing. The solution it is modeled after is this one:

$('#inputId').keydown(function (e) {
  if (e.which == 13 && $('.pac-container:visible').length) return false;
});

from the answer linked above. I modified this slightly so that it does not depend on the SearchBox having a particular class defined by Google and out of my control.

Upvotes: 1

adam0101
adam0101

Reputation: 30995

Is this getting submitted to a server? If so, it's probably a race condition. The form isn't waiting for the hidden fields to get set before submitting to the server. Regardless of whether you set the values from within the form submit event or the places_changed event of the SearchBox, you will still need to either prevent the enter key from submitting the form to the server or prevent the form from being submitted via user action so you can programmatically submit it later when your data is set.

To disable the enter key from submitting the form, look here: Google Autocomplete - enter to select

To disable the form submission, do as Juan suggested and include e.preventDefault();

Upvotes: 1

Juan Lago
Juan Lago

Reputation: 1048

I think that reason why the submit event handler is triggered when you press the enter button, but without places as an empty array is because the event handler is executed before than the initSearchBox function. It is possible that you previosly executed the initSearchBox so you had attached the submit event handler.

My recommendations is to replace your code by this one:

$('#searchform').submit(function (e) {
      var KCLatLng = new google.maps.LatLng({lat: 39.093201, lng: -94.573419});
      var bounds = new google.maps.LatLngBounds(KCLatLng);

      var input = $('#spotsearch')[0];
      var searchBox = new google.maps.places.SearchBox(input);
      searchBox.setBounds(bounds);
      
      var places = searchBox.getPlaces();
      
      if (places) {
            var spotLat = searchBox.getPlaces()[0].geometry.location.lat();
            var spotLng = searchBox.getPlaces()[0].geometry.location.lng();
            $('#latitude').val(spotLat);
            $('#longitude').val(spotLng);
      }

      // Prevent to perform a "real" submit (so page is not reloaded or redirected)
      e.preventDefault();

    });

In this way all the entire search code is going to be executed when the form is submitted.

Upvotes: 0

Related Questions