I have implemented Elastic's Search-UI on my website, where the user can enter their search term on the parent page and when they submit their search the results show up in a modal. The modal displays the search results and also has another search box the user can search again in (Search results from modal search box are displayed in modal too). This is implemented in React, I will share the source code below.
My bug:
When the user enters their search on the parent page there is this weird lag issue I cannot figure out how to fix where say the search term is "computer science", if this is typed quickly or copied into the search box only part of the search term is searched like "computer sc" which is not going to work for this site. I have added a 900ms timeout before the modal opens that "fixes" this, but it doesnt work every time and shouldn't be necessary. I will note that the search in the modal does NOT have this issue at all, there is no lag and the search works perfectly. Both searches were implemented very similarly as you can see in the code below and I have tried everything I can think of to try and fix the parent page search but no luck.
I have even added console log statements to validate that the search term used is fully captured in the search box and sent to the modal, they are both captured correctly, and yet only part of the search term is searched when the modal opens.
I am thinking there is a weird lag with the modal, but it is React's own modal implementation so I am starting to run out of ideas.
If anyone has any ideas please let me know, this is the only bug with this implementation but it is big enough that we cant put it out in prod with this type of behavior, thank you in advance
Screenshots showing the issue:
With no 900ms timeout, and the search term is copied, none of the search term shows up in the modal:
Source Code:
App.js (Parent page that opens modal)
import React, { useState } from "react";
import Modal from "./Components/Modal/Modal";
import "./App.css";
import { config } from "./config";
import {
ErrorBoundary,
SearchProvider,
SearchBox,
} from "@elastic/react-search-ui";
import { closeModal } from "./Utils/utils.js";
/**
* Contains logic to perform a search and open the search results modal
* @returns JSX for page
*/
export default function App() {
const [modalOpenState, setModalState] = useState(false);
const [inputText, setInputText] = useState("");
return (
<div>
<div>
<SearchProvider config={config}>
<ErrorBoundary>
<SearchBox
inputProps={{ placeholder: "Search this site" }}
onSubmit={(searchTerm) => {
{
/* setTimeout(() => {
setModalState(true);
}, 850); */
}
console.log(`searchTerm in App: ${searchTerm}`);
setModalState(true);
setInputText(searchTerm);
}}
searchAsYouType={true}
autocompleteSuggestions={false}
autocompleteMinimumCharacters={3}
debounceLength={0}
defaultQuery={inputText}
autocompleteResults={{
sectionTitle: "Results",
titleField: "title",
urlField: "url",
shouldTrackClickThrough: true,
clickThroughTags: ["test"],
}}
/>
</ErrorBoundary>
</SearchProvider>
</div>
{/* Opens modal based on state */}
{modalOpenState && (
<Modal
showModal={setModalState}
open={setModalState}
close={() => {
setModalState(false);
closeModal();
}}
inputText={inputText}
/>
)}
</div>
);
}
Modal.js
import React from "react";
import ReactDOM from "react-dom";
import "./Modal.css";
import {
updateAnchorTagsToOpenInParent,
useLockBodyScroll,
useEscapeKey,
} from "../../Utils/utils.js";
import {
ErrorBoundary,
SearchProvider,
SearchBox,
Results,
PagingInfo,
ResultsPerPage,
Paging,
WithSearch,
} from "@elastic/react-search-ui";
import { Layout } from "@elastic/react-search-ui-views";
import "@elastic/react-search-ui-views/lib/styles/styles.css";
import { config } from "../../config";
import FocusLock from "react-focus-lock";
/**
* Displays results from SUI search on a page within modal
* @param {*} showModal Sets state for showing modal
* @param {*} searchResultsURL The URL for the page opened in modal
* @returns JSX for modal
*/
export default function Modal({ open, close, inputText }) {
console.log(`searchTerm in Modal: ${inputText}`);
React.useEffect(() => {
// Update anchor tags to open in parent window
updateAnchorTagsToOpenInParent();
}, []);
// Call hook to lock body scroll when modal is opened
useLockBodyScroll();
// Escape key logic
const sendNo = () => showModal(false);
useEscapeKey(sendNo);
// Return null if modalState open is false
if (!open) return null;
return ReactDOM.createPortal(
<>
<div
className="modalBackground"
onClick={() => {
// close modal when outside of modal is clicked
close();
}}
/>
<div className="modalContainer">
<FocusLock>
<SearchProvider config={config}>
<WithSearch
mapContextToProps={({ wasSearched, searchTerm }) => {
console.log(`searchTerm in WithSearch: ${inputText}`); // Add this line
return { wasSearched };
}}
>
{({ wasSearched }) => {
return (
<div className="App">
<ErrorBoundary>
<Layout
header={
<SearchBox
inputProps={{ placeholder: "Search this site" }}
id="modalSearchBox"
autocompleteMinimumCharacters={3}
searchAsYouType={true}
autocompleteResults={{
sectionTitle: "Results",
titleField: "title",
urlField: "url",
shouldTrackClickThrough: true,
clickThroughTags: ["test"],
}}
autocompleteSuggestions={false}
debounceLength={0}
defaultQuery={inputText}
/>
}
bodyContent={
<Results
titleField="title"
urlField="url"
shouldTrackClickThrough={true}
/>
}
bodyHeader={
<React.Fragment>
{wasSearched && <PagingInfo />}
{wasSearched && <ResultsPerPage />}
</React.Fragment>
}
bodyFooter={<Paging />}
/>
</ErrorBoundary>
</div>
);
}}
</WithSearch>
</SearchProvider>
</FocusLock>
<div>
<button
type="button"
className="closeButton"
data-dismiss="modal"
aria-label="Close"
onClick={close}
>
X
</button>
</div>
</div>
</>,
document.getElementById("portal")
);
}
Thank you again in advance!!!