Home > Net >  focusout() selector not working with search box
focusout() selector not working with search box

Time:12-06

The focusout function prevents the user from redirecting to the title page whenever the user clicks on a title in the search results. It works as intended when it comes to closing the search results whenever I click on a different element on the page, but the search results also closes whenever I click on them.

I have tried using the blur function as well as hide() and show() but I get the same results. I get that I have .result display none but that shouldn't prevent me from clicking on a search result? Whats wrong here?

// jquery.js

$(document).ready(function() {
  $('.search-box input[type="text"]').on("keyup input", function() {
    /* Get input value on change */
    var inputVal = $(this).val();
    var resultDropdown = $(this).siblings(".result");
    if (inputVal.length) {
      $.get("includes/searchbar.inc.php", {
        term: inputVal
      }).done(function(data) {
        // Display the returned data in browser
        resultDropdown.html(data);
        $('.result').css('display', 'block');

        $("#searchboxy").focusout(function() {
          $('.result').css('display', 'none');
        });
        $("#searchboxy").focusin(function() {
          $('.result').css('display', 'block');
        });

      });
    } else {
      resultDropdown.empty();

    }
  });

  // Set search input value on click of result item
  $(document).on("click", ".result", function() {
    $(this).parents(".search-box").find('input[type="text"]').val($(this).text());
    $(this).parent(".result").empty();
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- header.php -->

<div  id="searchboxy">
  <input type="text" autocomplete="off" placeholder="Search for a game or genre..." />
  <div  id="resultsearch"></div>
</div>

CodePudding user response:

The main problem in your code was having a focusout event handler that was triggering every time the search input was going to loose focus.. and that event was going to occur also when clicking on the results.

Unfortunately such event would occur before the click event occurred on the results, so that as soon as you hide them in the first handler, the click handler was not going to trigger anymore.

A quick way to implement the same behaviour but having a clue of which element was clicked to better perform a logic based on a condition, is to just attach a click event handler to the whole document and each time check if the clicked element has the #searchboxy parent or not. In the first case it will hide the results and in the second case it won't.

For the sake of the demo I invented a custom result from your api that was not clear what kind of data was going to return. The weird thing is that you just attached its output to the result html.. I left it untouched.

I also changed the way you captured the click event on the result items.. Attaching the event handler once only to the parent results.

//makeSearch is replacing your fetch to an unreachable url
//but you didn't explain what's supposed to return.. so I'm inventing a raw html
const makeSearch = (term) => {
  return new Promise((resolve, reject) => {
    resolve(`
      <ul>
        <li>Result1</li>
        <li>Result2</li>
        <li>Result3</li>
      </ul>`
    );    
  });
}

//on click on the whole document
$(document).on('click', function(event){  
  //if the clicked element doesn't belong to the group #searchboxy
  if(!event.target.closest('#searchboxy')){
    //hides the .result
    $('.result').css('display', 'none');
  }
});

//on focusin on the input text, shows the .result
$("#searchboxy").on('focusin', function() {      
  $('.result').css('display', 'block');
});

//on click on the .result box...
$(document).on("click", ".result", function(event) {  
  const textOfClickedResultElement = event.target.innerText;  
  $(this).parents(".search-box").find('input[type="text"]').val( textOfClickedResultElement);
  $(this).parent(".result").empty();
});

$(document).ready(function() {

  $('.search-box input[type="text"]').on("keyup input", function() {
    /* Get input value on change */
    var inputVal = $(this).val();
    var resultDropdown = $(this).siblings(".result");
    if (inputVal.length) {
      
      //$.get("includes/searchbar.inc.php", {
      //  term: inputVal
      //})
      
      //I replaced your search request with a bogus promise for the sake of the demo
      makeSearch(inputVal)
        .then(function(data) {          
          // Display the returned data in browser
          //!this is weird.. you are outputting the fetched data as is in the html! (I left it untouched)
          resultDropdown.html(data);
          $('.result').css('display', 'block');
        });
    } else {
      resultDropdown.empty();
    }
  });
  
});
.info{
  margin-bottom: 10px;
}

#searchboxy{
  border: dashed 3px lightgray;
  padding: 10px 10px;
}

#searchboxy input{
  width: 15rem;
}

#resultsearch{
  border: solid 1px gray;
  display: none;
  margin-top: 1rem;
}

#resultsearch li{
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- header.php -->

<div >
  Start typing inside the textbox to show the search results.<br>
  Clicking anywhere outside the dashed borders, will hide the results.<br>
  Giving focus to the textbox, will show the results.<br>
  If you click any single result item, its value will be pushed in the search box.
</div>

<div  id="searchboxy">
  <input type="text" autocomplete="off" placeholder="Search for a game or genre..." />
  <div  id="resultsearch"></div>
</div>

CodePudding user response:

Try this CDN for test May be it works

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
  • Related