A "From" form that include airports

Hi,

My website - www.flilu.com is a a flight engine that look for flights.
However, in my “From” form there you can’t look for specific airports.
For example - www.kayak.com “from” field, you just write TL… and it gives you Tel Aviv airport as an option.

  1. How can I include all the airports? Do I need to request a specific API?
  2. How does the form auto complete?

Hey Eilon,

You can use the $w.HtmlComponent (HTML Code element in the editor) to embed the code. As an example, I used the code from the Airport Autocomplete codepen (A PEN BY Jesse Gavin).

I hope this helps,

Yisrael

Hi again Eilon,

Add a $w.HtmlComponent to a page from the More component menu:

Then embed the code in the Edit the Code panel of the HtmlComponent :


And now, hold on to your hat. Add the following code to the Add your code here box:

<!doctype html>
<html>
<head>

<style>

body {
 margin: 50px;
}

.form-group {
 margin-bottom: 20px;
}
.control-label {
 display: block;
}

.autocomplete-wrapper {
 position: relative;
 
  input {
 width: 100%;
  }
}
.autocomplete-results {
 position: absolute;
 background: white;
 z-index: 1;
 top: 100%;
 left: 0;
 font-size: 13px;
 border: solid 1px #ddd;
 border-top-width: 0;
 border-bottom-color: #ccc;
 box-shadow: 
 0 5px 10px rgba(0, 0, 0, 0.2);
}

.autocomplete-result {
 padding: 12px 15px;
 border-bottom: solid 1px #eee;
 cursor: pointer;
}

.autocomplete-result:last-child {
 border-bottom-width: 0;
}

.autocomplete-location {
 opacity: .8;
 font-size: smaller;
}

$iPlus: 0;
@for $i from 0 through 7 {
  $iPlus: $i + 1;
  .autocomplete-results[data-highlight='#{$i}'] > :nth-child(#{$iPlus}) {
 color: white;
 background: #26C9FF;
 border-bottom-color: #26C9FF;
 outline: solid 1px darken(#26C9FF, 10%);
  }
}

</style>

<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.1/lodash.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>
<script src='https://unpkg.com/fuse.js@2.5.0/src/fuse.min.js'></script>
<script src='https://screenfeedcontent.blob.core.windows.net/html/airports.js'></script>

</head>

<body>


<div class="form-group">
 <label class="control-label">Enter an Airport</label>
 <input id="autocomplete" type="text" />
 </div>
 
 <div class="form-group">
 <label class="control-label">Another field (so we can test TAB behavior)</label>
 <input type="text" />
 </div>

<script type="text/javascript">

 var options = {
        shouldSort: true,
        threshold: 0.4,
        maxPatternLength: 32,
        keys: [{
        name: 'iata',
        weight: 0.5
        }, {
        name: 'name',
        weight: 0.3
        }, {
        name: 'city',
        weight: 0.2
        }]
    };
 
 var fuse = new Fuse(airports, options)
 
 
 var ac = $('#autocomplete')
        .on('click', function(e) {
 e.stopPropagation();
        })
        .on('focus keyup', search)
        .on('keydown', onKeyDown);
 
 var wrap = $('<div>')
        .addClass('autocomplete-wrapper')
        .insertBefore(ac)
        .append(ac);
 
 var list = $('<div>')
        .addClass('autocomplete-results')
        .on('click', '.autocomplete-result', function(e) {
 e.preventDefault();
 e.stopPropagation();
 selectIndex($(this).data('index'));
        })
        .appendTo(wrap);
 
 $(document)
        .on('mouseover', '.autocomplete-result', function(e) {
 var index = parseInt($(this).data('index'), 10);
 if (!isNaN(index)) {
 list.attr('data-highlight', index);
        }
        })
        .on('click', clearResults);
 
 function clearResults() {
 results = [];
 numResults = 0;
 list.empty();
    }
 
 function selectIndex(index) {
 if (results.length >= index + 1) {
 ac.val(results[index].iata);
 clearResults();
        }  
    }
 
 var results = [];
 var numResults = 0;
 var selectedIndex = -1;
 
 function search(e) {
 if (e.which === 38 || e.which === 13 || e.which === 40) {
 return;
        }
 
 if (ac.val().length > 0) {
 results = _.take(fuse.search(ac.val()), 7);
 numResults = results.length;
 
 var divs = results.map(function(r, i) {
 return '<div class="autocomplete-result" data-index="'+ i +'">'
 + '<div><b>'+ r.iata +'</b> - '+ r.name +'</div>'
 + '<div class="autocomplete-location">'+ r.city +', '+ r.country +'</div>'
 + '</div>';
            });
 
 selectedIndex = -1;
 list.html(divs.join(''))
            .attr('data-highlight', selectedIndex);
 
        } else {
 numResults = 0;
 list.empty();
        }
    }
 
 function onKeyDown(e) {
 switch(e.which) {
 case 38: // up
 selectedIndex--;
 if (selectedIndex <= -1) {
 selectedIndex = -1;
            }
 list.attr('data-highlight', selectedIndex);
 break;
 case 13: // enter
 selectIndex(selectedIndex);
 break;
 case 9: // enter
 selectIndex(selectedIndex);
 e.stopPropagation();
 return;
 case 40: // down
 selectedIndex++;
 if (selectedIndex >= numResults) {
 selectedIndex = numResults-1;
            }
 list.attr('data-highlight', selectedIndex);
 break;
 
 default: return; // exit this handler for other keys
        }
 e.stopPropagation();
 e.preventDefault(); // prevent the default action (scroll / move caret)
    }
 
 </script>
</body>
</html>

OK, so that’s insane, right? But, it actually works. You can play with this, or look for some others that might work for you better. I just wanted to give you an idea of what you can do.

In order to use the autocomplete in your own web page, you’ll have to pass messages back and forth between the page and the HtmlComponent. For more information, read Working with the HTML Component in Wix Code.

And now, it’s time for me to take a nap.

Good luck and have fun,

Yisrael

Hi!
Thank you for your help,
I have played a bit and now I have a beautiful form using bootstrap 4.

The only problem now is that when I have results… it covers the rest of the forms and I can’t click on them.
(Because the html form is in front of the other forms…)

Is there anything I can add to the HTML code so when I have text the element of the HTML, the form goes to the front and when I finish texting and pick one of the options it will go to the back again?
I want to be able to click on the other forms…

look at my website for example for my current situation:
www.flilu.com

Hay Eilon,

To get the best results you can drop the IFrame and develop the relevant experience with Wix Code. The problem with an IFrame is that it requires to have space for the dropdown, which is over the date inputs and prevents interaction with them.

The visual design -
Place a repeater under the airport selector, on top of the date selectors (so that it hides them). In the repeater place a text element. Set the repeater to be hidden.

Now, implement an on focus event for the airport selector to show the repeater. On click in the repeater, set the selection to the airport input and hide the repeater.

You can use fuse.js for the search itself and the list of airports from airports.js (just copy the json file).

Hi, I’m trying to understand if there are ways to bring google autocomplete/search box function into wix code. (e.g. into address form) Above example seems to suggest external library could be used, but answer from another post mentioned external javascript module can’t be used?

Could you please help us understand how google places API/autocomplete/search box could be implemented into wix code websites?

You can perform the query using a query URL. The Google map docs have plenty of information on how to build the URL.

You can put the autocomplete in a $w.HtmlComponent, but that takes up a set amount of screen space when you do that. You need to make the HtmlComponent big enough to handle the dropdown of the suggestions.

It’s a bit cleaner to add a repeater under a $w.TextInput component. Then the suggestions from the autocomplete query can be put into the repeater which is hidden using .hide(). When you have results you .show() the repeater.

I understand that with $w.HtmlComponent, you can put in codes that would produce a search box with google autocomplete function. Is this what you mean by query URL?

Regarding a repeater under $w.TextInput component, why would it be cleaner? If results from $w.HtmlComponent are copied to $w.TextInput component exactly, then wouldn’t the only difference be the shape/design of the boxes? Are there other shortcomings associated with $w.HtmlComponent boxes that require use of repeaters?

I tried setting up a new text component and receive data from HTML component, but it doesn’t seem to be
working. Any thoughts on why this might be the case?

  1. Page code
    $w.onReady(function () {
    });

export function ClickNextButton_click(event, $w) {
// Receive autocompleted address from html component
$w(“#PickupAutocomplete”).onMessage( (event) => { // this is HTML component
$w(“#pickupAddressReceived”).text = event.data; // this is new text box; hidden on load
console.log(“Pickup Autocompleted data is " + $w(”#pickupAddressReceived").text);
} );

  1. HTML code
input { height: 45px; width: 270px; padding-left: 10px; border-radius: 6px; border: 1px solid rgb(186, 178, 178); box-shadow: 0px 0px 1px #EFEFEF; }
<script> 
  var input = document.getElementById('autocomplete'); 
  var options = { 
      componentRestrictions: {country: 'kr'} 
  }; 
  var autocomplete = new google.maps.places.Autocomplete(input, options); 

  autocomplete.addListener('place_changed', function() { 
      var place = autocomplete.getPlace(); 
      if (!place.geometry) { 
        // User entered the name of a Place that was not suggested and 
        // pressed the Enter key, or the Place Details request failed. 
        window.alert("No details available for input: '" + place.name + "'"); 
      return; 
      } 
    }) 
</script> 

What I want is to be able to extract from HTML component is the lat, lng value of the “place” (place.geometry.location). What would be the best way to do that? I tried adding “var placeGeoCoordinate = place.geometry.location;”, but then autocomplete query stops working.

For anybody who’s interested in this feature: the Address Input Editor Element has been released .