0
\$\begingroup\$

I am working on an e-commerce website.

The home page has 2 inputs: Looking for and Location. The user would enter their desired product and location and click on Search as shown below:

enter image description here

The first input (i.e. Looking for) has autocomplete functionality and when the user clicks on it, it opens a list of suggestions. I am using the jQuery UI Autocomplete tool to build the suggestions. The suggestions come from Elasticsearch (in this example I am using a static array to demonstrate the behavior).

The problem I'm solving is that on a mobile device, the autocomplete's suggestions opens under the input and the keyboard pops up and hides the suggestions as shown below:

enter image description here

What I want to do is to highlight the autocomplete input when it is focussed in mobile devices. That is to bring it to the top of the screen and hide everything else. This is what ebay does on mobile devices.

The code

I have placed my autocomplete input inside a sticky-container and when the container is focused I add active class to the sticky-container which would make its position static.

Note: I am using media queries to do this for mobile devices only, however I could not get the media query working in the snippet below, so I kept them commented.

var elasticSearchSuggestions = [
  "Armchair", "Apple", "Ball", "Bed", "Book", "Car", "Cooking", "Desk", "Earaser", "Football", "Games",
  "Hammer", "Headphone", "iPhone", "Iron", "Job", "King size bed", "Lamp", "Mobile", "Nail", "Orange",
  "Paper", "Pencil", "Pool", "Rail", "Running Shoes", "Queen size bed", "Saw", "Shoes", "Table", 
  "Tools", "Toyota", "Umbrella", "Window", "Xerox", "Yarn", "Zoo"
];

function bringStickyInputToTopOfThePageOnMobile() {
  $("#autocompleteInput").on("click", function() {
    $(this).closest('.sticky-container').addClass('active');
  });

  $("#autocompleteInput").on("blur", function() {
    $(this).closest('.sticky-container').removeClass('active');
  });
}

function isMobileDevice() {
  if (Modernizr.mq('(max-width: 767px)')) {
    return true;
  }
  return false;
}

$(document).ready(function() {
  $("#autocompleteInput").autocomplete({
    source: elasticSearchSuggestions,
    position: {
      collision: "flip"
    }
  });
  
  // if (isMobileDevice()) {
    bringStickyInputToTopOfThePageOnMobile();
  // }
});
/* All the CSS is inside this media query
   * @media (max-width:767px) 
   */

.sticky-container.active {
  top: 0px;
  left: 0px;
  position: fixed;
  width: 100%;
  height: 100%;
  padding: 65px 15px;
  z-index: 1;
  background-color: #fff;
  display: block !important;
}

.sticky-container.active:before {
  display: block !important;
  content: 'x';
  font-size: 25px;
  position: absolute;
  top: 25px;
  right: 75px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>

<body>
  <nav class="navbar navbar-expand-sm bg-light">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a class="nav-link" href="#">Home</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Products</a>
      </li>
    </ul>
  </nav>
  <br>

  <div class="container">
    <h3>Search Products</h3>
    <hr/>
    <form>
      <div class="form-group sticky-container">
        <label>Looking for</label>
        <input id="autocompleteInput" type="text" class="form-control" placeholder="Looking for">
      </div>
      <div class="form-group sticky-container">
        <label>Location</label>
        <input type="text" class="form-control" id="locationInput" placeholder="Location">
      </div>
      <button type="submit" class="btn btn-primary">Search</button>
    </form>
</body>

</html>

Note: I am using position: { collision: "flip" } for jQuery UI's autocomplete which means it should open the suggestion box on the top, if the input is at the bottom of the page... however I think using this method, there is still more room for the autocomplete suggestions box.

\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

Using CSS instead of JavaScript to apply styles

If only there was browser support for :has() pseudo-selector - then the JavaScript function bringStickyInputToTopOfThePageOnMobile() could be eliminated. Another option would be to use :focus-within but additional selectors would need to be applied to limit the functionality to only the container(s) with an autocomplete.

jQuery does have support for using a :has() selector but that would only be in JavaScript calls to its DOM selection functions.

jQuery DOM-ready syntax:

As of jQuery 3.0, only $(handler) is recommended; the other syntaxes still work but are deprecated.1

So that ready callback registration can be simplified from

$(document).ready(function() {
  $("#autocompleteInput").autocomplete({

to:

$(function() {
  $("#autocompleteInput").autocomplete({

Or use an arrow function expression:

$(_ => {
  $("#autocompleteInput").autocomplete({
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.