Reputation: 11
I've created a simple search bar using a text input field.
An onkeyup event handles the searching of results and displays relevant matches directly beneath the search bar. For each of the returned search results, an onclick event is used to select the result. The result of this being that a relevant element is unhidden from a list further down the page, and scrollIntoView is used to display this element to the user.
On desktop, everything works without issue. On mobile when selecting the input field, this brings up the on-screen keyboard, and I believe the presence of this is interfering with scrollIntoView executing correctly.
Note that this issue is present whilst testing with Chrome for Android, although I will need to ensure that behaviour works as expected across all mobile browsers.
Selecting a search result whilst the on-screen keyboard is present does execute all other code correctly, in that the relevant element is unhidden from the list further down the page (if you scroll down to see it manually). When the search result is selected, the on-screen keyboard disappears as well, but the page view does not change and we remain at the top of the page.
Manually closing the on-screen keyboard (after typing into the input field but before selecting a search result) then selecting the search result, results in scrollIntoView executing as expected.
This seems as though it would be quite common to select an element whilst the on-screen keyboard is present and expect scrolling called by JS, but all my searching only seems to throw up discussions on how to hide/display the on-screen keyboard.
Any ideas on this?
Input Field (HTML):
<input id="searchBar" name="searchBar" placeholder="Type To Search" onkeyup="searchBarSearchForItem();" onfocus="searchBarSearchForItem();" class="">
Search Bar Results (HTML/PHP):
<div id="searchBarResultsContainer" class="hidden">
<ul>
<li id="searchBarResult-NoResults" class="">No Results</li>
<? foreach ($allItems as $item) { ?>
<li id="searchBarResult-<?=$item->code;?>" onclick="searchBarSelectProduct('<?=$item->code;?>');" class="hidden">
<div class="flex">
<p class=""><?=$item->name;?></p>
<div class="flex-grow"></div>
</div>
</li>
<? } ?>
</ul>
</div>
searchBarSelectProduct function (JS):
function searchBarSelectProduct(itemCode) {
// Hide the results container
let searchResultContainerElement = document.getElementById("searchBarResultsContainer");
searchResultContainerElement.classList.add("hidden");
// Unhide the item entry further down the page, then ScrollIntoView
let itemCard = document.getElementById("itemCard-" + itemCode);
itemCard.classList.remove("hidden");
itemCard.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"});
}
Upvotes: 1
Views: 606
Reputation: 11
I found a solution to this requiring the use of JS to 'manually' close the on-screen keyboard, combined with the subsequent call of the "scrollIntoView" function being called from within a setTimeout function.
I am assuming this works because it allows for sufficient time for the keyboard to close itself allowing the scroll to work uninterrupted
The code for the manual keyboard close I took from this question here: How can I hide the Android keyboard using JavaScript?
Resulting in the following:
function hideKeyboard(element) { // Pass the input element from which the keyboard was opened
element.setAttribute('readonly', 'readonly'); // Force keyboard to hide on input field.
element.setAttribute('disabled', 'true'); // Force keyboard to hide on textarea field.
setTimeout(function() {
element.blur(); //actually close the keyboard
// Remove readonly attribute after keyboard is hidden.
element.removeAttribute('readonly');
element.removeAttribute('disabled');
}, 100);
}
And the updated searchBarSelectProduct function is:
function searchBarSelectProduct(itemCode) {
let searchBarInput = document.getElementById("searchBar");
hideKeyboard(searchBarInput);
setTimeout(function() {
// Hide the results container
let searchResultContainerElement = document.getElementById("searchBarResultsContainer");
searchResultContainerElement.classList.add("hidden");
// Unhide the item entry further down the page, then ScrollIntoView
let itemCard = document.getElementById("itemCard-" + itemCode);
itemCard.classList.remove("hidden");
itemCard.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"});
}, 100);
}
Upvotes: 0