How to make Dropdown in ReactJs from Query and get the value - javascript

Sorry if I ask again, I try to make dropdown from array in my database then use the dropdown to take the value I want looping the array to the dropdown in here but still not showed
//tipe akademik
//define state
const [postsTipe, setPostsTipe] = useState([]);
//useEffect hook
useEffect(() => {
//panggil method "fetchData"
fectDataTipe();
}, []);
//function "fetchData"
const fectDataTipe = async () => {
//fetching
const responseTipe = await axios.get('http://localhost:3000/api/tipe_akademik');
//get response data
const dataTipe = await responseTipe.data.data;
//assign response data to state "posts"
setPostsTipe(dataTipe);
}
const Dropdown = () => {
// dropdown props
const [dropdownPopoverShow, setDropdownPopoverShow] = React.useState(false);
const btnDropdownRef = React.createRef();
const popoverDropdownRef = React.createRef();
const openDropdownPopover = () => {
createPopper(btnDropdownRef.current, popoverDropdownRef.current, {
placement: "bottom-start",
});
setDropdownPopoverShow(true);
};
const closeDropdownPopover = () => {
setDropdownPopoverShow(false);
};
return (
<>
<a
className="text-blueGray-500 block"
href="#pablo"
ref={btnDropdownRef}
onClick={(e) => {
e.preventDefault();
dropdownPopoverShow ? closeDropdownPopover() : openDropdownPopover();
}} >
<div class="relative inline-block text-left">
<div>
<button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="menu-button" aria-expanded="true" aria-haspopup="true">
Tipe Akademik
</button>
</div>
</div>
</a>
<div
ref={popoverDropdownRef}
className={
(dropdownPopoverShow ? "block " : "hidden ") +
"bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg min-w-48"
}
>
{postsTipe.map((kategori)=> {
return(<>
<a
href="#pablo"
className={
"text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700"
}
onClick={(e) => e.preventDefault()}
>
{kategori.tipe_akademik}
</a> /</> )})}
</div>
</>
);
};
export default Dropdown;
Then I call it to my input form with import from dropdown and I want take the value in form and its still wrong. I dont know how to take the the value from import the dropdown named TipeDropdown
import TipeDropdown from "components/Dropdowns/Dropdown";
method "storePost"
const storePost = async (e) => {
e.preventDefault();
//send data to server
await axios.post('http://localhost:3000/api/akademik_a/store', {
tipeA: TipeA,
})
.then(() => {
//redirect
history.push('/admin/dafgur');
})
.catch((error) => {
//assign validation on state
setValidation(error.response.data);
})
};
export default function InputAkademik({ color }) {
return (
<>
<form onSubmit={ storePost }
<input className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
placeholder="" />
<div className="field mt-5">
<label className="label">Tipe Akademik</label>
<div className="controls">
<TipeDropdown value={TipeA} onChange={(e) => setTipe(e.target.value)}/>
<input type="text" className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150" placeholder="" value={TipeInput} onChange={(e) => TipeInput(e.target.value)} />
</div>
</div> </div>
</>
);
};

Related

Submitting form in react modal not working - no event triggered

I leverage the npm package react-modal (https://www.npmjs.com/package/react-modal).
I want to submit a form that resides within the modal.
For some reason when clicking on 'Abschicken', nothing happens. The handleSubmitfunction is never triggered as I do not see any console logs.
What do I miss here?
import { useState, useRef } from "react";
import Modal from "react-modal";
import LogoHori from "../../../public/images/logo_hori.png";
import Image from "next/image";
const customStyles = {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
position: "absolute",
},
overlay: { zIndex: 1000 },
};
Modal.setAppElement("#__next");
// Make sure to bind modal to your appElement (https://reactcommunity.org/react-modal/accessibility/)
const ContactModal = ({ buttonStyles }) => {
const [modalIsOpen, setIsOpen] = useState(false);
const [isValidEmail, setIsValidEmail] = useState(true);
const [successfulSubmission, setSuccessfulSubmission] = useState("");
const lastNameInputElement = useRef();
const firstNameInputElement = useRef();
const emailInputElement = useRef();
const messageInputElement = useRef();
const validate = (email) => {
const expression =
/(?!.*\.{2})^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")#(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i;
return expression.test(String(email).toLowerCase());
};
function openModal() {
setIsOpen(true);
}
function afterOpenModal() {
// references are now sync'd and can be accessed.
}
function closeModal() {
setIsOpen(false);
}
const handleSubmit = async (event) => {
console.log("clicked");
event.preventDefault();
const data = {
lastName: lastNameInputElement.current?.value,
firstName: firstNameInputElement.current?.value,
email: emailInputElement.current?.value,
message: messageInputElement.current?.value,
};
if (!validate(data.email)) {
setIsValidEmail(false);
return;
}
setIsValidEmail(true);
console.log(data);
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data),
};
try {
const result = await fetch(
"https://someEndpoint",
requestOptions
);
if (result.status == 200) {
setSuccessfulSubmission(true);
setTimeout(closeModal, 5000);
} else {
throw new Error();
}
} catch {
console.log(error);
setSuccessfulSubmission(false);
}
};
return (
<div>
<button className={buttonStyles} onClick={openModal}>
Anfrage
</button>
<Modal
isOpen={modalIsOpen}
onAfterOpen={afterOpenModal}
onRequestClose={closeModal}
style={customStyles}
contentLabel="Nido Surf"
>
<div className="w-[300px] md:w-[600px]">
<Image src={LogoHori} alt="nido-surf-logo" width={300} />
<form action="Post" onSubmit={handleSubmit} className="mt-5 flex flex-col justify-between">
<label htmlFor="name" className="font-bold mb-2">
Nachname
</label>
<input
ref={lastNameInputElement}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline"
id="name"
type="text"
placeholder="Nachname"
/>
<label htmlFor="firstname" className="font-bold my-2">
Vorname
</label>
<input
ref={firstNameInputElement}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline"
id="firstname"
type="text"
placeholder="Vorname"
/>
<label htmlFor="email" className="font-bold my-2">
Email-Adresse
</label>
<input
ref={emailInputElement}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline"
id="email"
type="text"
placeholder="Email-Adresse"
/>
{!isValidEmail && (
<p className="text-secondary-red-200">
Deine Email-Adresse ist ungültig!
</p>
)}
<label htmlFor="message" className="font-bold my-2">
Nachricht
</label>
<textarea
ref={messageInputElement}
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline"
name="message"
id="message"
cols="30"
rows="10"
></textarea>
</form>
<div className="mt-5 flex gap-x-4 justify-center items-center">
<button
type="submit"
className="w-full text-white rounded-md py-4 hover:bg-secondary-green-300 bg-secondary-green-400"
>
Senden
</button>
<button
className="w-full text-white rounded-md py-4 hover:bg-secondary-red-100 bg-secondary-red-300"
onClick={closeModal}
>
Abbrechen
</button>
</div>
</div>
</Modal>
</div>
);
};
export default ContactModal;
It's not triggering the submit event because your button is not inside the form. Move the below div above the closing tag of form. Also, notice this type="button" on the second button:
<div className="mt-5 flex gap-x-4 justify-center items-center">
<button
type="submit"
className="w-full text-white rounded-md py-4 hover:bg-secondary-green-300 bg-secondary-green-400"
>
Senden
</button>
<button
className="w-full text-white rounded-md py-4 hover:bg-secondary-red-100 bg-secondary-red-300"
onClick={closeModal}
type="button"
>
Abbrechen
</button>
</div>

fetched data from firestore as initial value of useState it gives me udefined value

I want to set the fetched data from firestore as initial value of useState but it gives me undefined value because I want to update user profile and I don't know the user edits or updates which property because I want to keep the other properties of the user the same, only change the edited one.
I've tried this code, but it gives me this error:
Uncaught (in promise) FirebaseError: Function updateDoc() called with invalid data. Unsupported field value: undefined (found in field surname in document users/DQjpLaKYVgVuH9TeqNomIEyuMJB2)
import React, { useState, useEffect } from 'react';
import { useAuthState } from 'react-firebase-hooks/auth';
import { doc, onSnapshot, updateDoc } from "firebase/firestore";
import { auth, db } from '../../firebase';
export default function Form({ setEditForm }) {
const [user, setUser] = useState([]);
const [currentUser] = useAuthState(auth);
// fetching user information from firestore
useEffect(() => {
const getUser = async () => {
const docRef = await doc(db, 'users', currentUser.uid)
try {
await onSnapshot(docRef, (doc) => {
setUser({
...doc.data(), id: doc.id
})
})
} catch (e) {
console.log(e)
}
}
getUser()
}, [])
const [name, setName] = useState(user.firstName);
const [surname, setSurname] = useState(user.surname);
const [biography, setBiography] = useState(user.biography);
const [location, setLocation] = useState(user.location);
// updating user's profile
const updateProfile = async (e) => {
e.preventDefault();
const docRef = doc(db, 'users', currentUser.uid);
await updateDoc(docRef, {
firstName: name,
surname: surname,
biography: biography,
location: location
})
}
console.log(user)
return (
<form
onSubmit={updateProfile}
className="flex flex-col w-4/6 lg:w-3/6"
>
<div className="lg:flex lg:flex-row lg:justify-between lg:gap-6">
<div className="lg:flex lg:flex-col lg:w-1/2">
<h2 className="text-left text-[#4699C2] font-bold py-2">Name: </h2>
<div className="border border-gray-300 rounded-md">
<input
type="text"
placeholder={name}
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full py-2 px-4 opacity-50 focus:opacity-100"
/>
</div>
</div>
<div className="lg:flex lg:flex-col lg:w-1/2">
<h2 className="text-left text-[#4699C2] font-bold py-2">Surname: </h2>
<div className="border border-gray-300 rounded-md">
<input
type="text"
placeholder={surname}
value={surname}
onChange={(e) => setSurname(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-2"
/>
</div>
</div>
</div>
<h2 className="text-left text-[#4699C2] font-bold py-2">Biograhpy: </h2>
<div className="border border-gray-300 rounded-md">
<textarea
onChange={(e) => setBiography(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-4"
>
{biography}
</textarea>
</div>
<h2 className="text-left text-[#4699C2] font-bold py-2">Location: </h2>
<div className="border border-gray-300 rounded-md">
<input
placeholder={location}
value={location}
onChange={(e) => setLocation(e.target.value)}
className="opacity-50 px-4 focus:opacity-100 w-full py-2"
/>
</div>
<div className="flex flex-row justify-center py-4">
<input
type="submit"
value="SAVE"
className="bg-[#4699C2] text-white fong-bold w-24 py-3 rounded-full mx-4 font-bold hover:bg-[#026FC2] hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out"
/>
<input
onClick={() => {
setEditForm(false);
}}
type="reset"
value="CANCEL"
className="bg-[#4699C2] cursor-pointer lg:bg-white hover:bg-[#026FC2] hover:text-white hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 focus:text-white active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out text-white lg:text-[#4699C2] lg:border lg:border-[#4699C2] fong-bold w-24 py-3 rounded-full font-bold"
/>
</div>
</form>
);
}
Answering this as community wiki, As suggested by #yograjtandel, instead of storing the response in one single state, first declare all the states like name, biography, surname, etc... to null. then in useState set all the states ex. setName(doc.data().Name).

React HeadlessUI ComboBox (autocomplete) - How to pass onClick action

I want to replace a text input with a Combobox from https://headlessui.dev/react/combobox
Now the Combobox internal mechanism is working, but I'm not able to filter my results with the selected item.
This was the initial search input:
const SearchBar = ({ journeys, setSearchResults }) => {
const handleSubmit = (e) => e.preventDefault();
const handleSearchChange = (e) => {
if (!e.target.value) return setSearchResults(journeys);
const resultsArray = journeys.filter(
(journey) =>
// journey.arr.toLowerCase().includes(e.target.value) ||
journey.dep.toLowerCase().includes(e.target.value)
);
setSearchResults(resultsArray);
};
return (
<header>
<form className="p-4" onSubmit={handleSubmit}>
<input
className="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
type="text"
id="search"
onChange={handleSearchChange}
/>
</form>
</header>
);
};
export default SearchBar;
and here is the new Combobox:
import { useState } from 'react';
import { Combobox } from '#headlessui/react';
import { MapPinIcon } from '#heroicons/react/24/outline';
import places from '../data/places';
const DepartureBox = ({ journeys, setSearchResults }) => {
const handleSubmit = (e) => e.preventDefault();
const handleSearchChange = (e) => {
if (!e.target.value) return setSearchResults(journeys);
const resultsArray = journeys.filter(
(journey) =>
// journey.arr.toLowerCase().includes(e.target.value) ||
journey.dep.toLowerCase().includes(e.target.value)
);
setSearchResults(resultsArray);
};
const [query, setQuery] = useState('')
const filteredPlaces = query
? places.filter((place) => place.name.toLowerCase().includes(query.toLowerCase()))
: []
return (
// <header>
// <form className="p-4" onSubmit={handleSubmit}>
// <input
// className="block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
// type="text"
// id="search"
// onChange={handleSearchChange}
// />
// </form>
// </header>
<div className="m-4">
<Combobox
onChange={(place) => {
// TODO: onChange={handleSearchChange}
handleSearchChange
}}
as="div"
className="relative max-w-xl rounded-md ring-1 ring-black/5 divide-y divide-gray-100 overflow-hidden"
>
<div className='flex items-center px-2'>
<MapPinIcon className="h-6 w-6 text-gray-500" />
<Combobox.Input
onChange={(event) => {
setQuery(event.target.value)
}}
className="w-full h-10 bg-transparent border-0 focus:ring-0 text-sm text-gray-800 placeholder:text-gray-400"
placeholder='Select Departure Place...'
/>
</div>
{filteredPlaces.length > 0 && (
<Combobox.Options className="py-4 text-sm max-h-40 overflow-y-auto">
{filteredPlaces.map((place) => (
<Combobox.Option key={place.id} value={place}>
{({ active }) => (
<div className={`space-x-1 px-4 py-2 ${active ? 'bg-indigo-600' : 'bg-white'}`}>
<span className={`font-medium ${active ? 'text-white' : 'text-gray-900'}`}>{place.name}</span>
<span className={`font-medium ${active ? 'text-indigo-200' : 'text-gray-400'}`}>in {place.id}</span>
</div>
)}
</Combobox.Option>
))}
</Combobox.Options>
)}
{
query && filteredPlaces && filteredPlaces.length === 0 && (
<p className='p-4 text-sm text-gray-500'>No places found.</p>
)
}
</Combobox>
</div>
);
};
export default DepartureBox;
For sure I'm missing something at the onChange={(place) => level, but as this is my second react component, I'm lost at that point. Any help would be very appreciated.
Here is the codesandbox: https://codesandbox.io/p/github/sinyayadynya/roadbook/draft/codesandbox

React: How to set up Edit Function in CRUD app to switch out whole components while keeping id

Hey Guys I'm pretty new to React and I'm running into a bit of a pickle here.
I'm making a simple CRUD website creator and I've got the add and delete function created and they work great! but I'm having trouble with the edit function.
I've based this on the this tutorial which works with String data-type
https://www.digitalocean.com/community/tutorials/react-crud-context-hooks
So in my mind this is how it should should work
I've got use state as passing an object with a couple of properties
const [selectedSection, setSelectedSection] = useState({
id: null,
section: {},
});
I've set the id to the current component I'm editing with
const currentSectionId = route.match.params.id;
in my useEffect I'm carrying over the current id with while setting the new compenent skipping the id in the current section
useEffect(() => {
const sectionId = currentSectionId;
const selectedSection = sections.find(
(currentSectionTraversal) => currentSectionTraversal.id === parseInt(sectionId)
);
setSelectedSection(selectedSection);},[currentSectionId, sections]);
const onSubmit = (e) => {
e.preventDefault();
editSection(selectedSection);
history.push("/");
console.log("selectedSection id",selectedSection.section, selectedSection.id)
};
and the button function to spread the selectedSection and change the only the requested value in the button.
const handleOnChange = (userKey, newValue) => setSelectedSection({ ...selectedSection, [userKey]: newValue });
in my render code I've got my button set up like
<button href="/" className="bg-green-400 w-mt hover:bg-green-500 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
value={selectedSection.section}
onChange={() => handleOnChange("section", QuickLinks)}
type="submit"
>Add Section</button>
Now I've tried different things like changing the data-type in the useState Object, having the setSelectedSection in use effect to change the SelectedSection.section
but in the console what I'm noticing is the button is not carrying the data over.
I've imported my compenent as Quicklinks but I'm not sure why it's not passing the component into the selectedSection.section
here is the entire code of the editSection
import React, { useState, useContext, useEffect} from "react";
import { useHistory, Link } from "react-router-dom";
import { GlobalContext } from "./GlobalState";
import QuickLinks from '../components/sections/quick_links/quickLinks';
import QuickLinksPreview from './images/quick-link.jpg';
export const EditSection = (route) => {
let history = useHistory();
const { sections, editSection } = useContext(GlobalContext);
const [selectedSection, setSelectedSection] = useState({
id: null,
section: {},
});
const currentSectionId = route.match.params.id;
useEffect(() => {
const sectionId = currentSectionId;
const selectedSection = sections.find(
(currentSectionTraversal) => currentSectionTraversal.id === parseInt(sectionId)
);
setSelectedSection(selectedSection);
}, [currentSectionId, sections]);
const onSubmit = (e) => {
e.preventDefault();
editSection(selectedSection);
history.push("/");
console.log("selectedSection id",selectedSection.section, selectedSection.id)
};
const handleOnChange = (userKey, newValue) => setSelectedSection({ ...selectedSection, [userKey]: newValue });
if (!selectedSection || !selectedSection.id) {
return <div>Invalid Employee ID.</div>;
}
return (
<React.Fragment>
<div className="w-full container mt-20 mx-auto">
<form onSubmit={onSubmit}>
<table>
<tbody>
{/* ----------------------------Item List Start COPY------------------------ */}
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center">
<div className="flex-shrink-0 h-40 w-50 shadow">
<img className="h-40 w-full " src={QuickLinksPreview} alt="" />
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm text-gray-900">Quick Links</div>
<div className="text-sm text-gray-500">Multi Card Quick Links<br></br>for Description and links</div>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-white-800"> Beta </span>
{/* Component Development Status
<span className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-black-800"> Constrution </span>
<span className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"> Active </span>
<span className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-black-800"> Testing </span>
*/}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">S03-S5</td>
{/* Pricing Levels as Structure
S = Labels that it is sections
02 = is the Template Id for Developers
S = Standard Price
3 = Price level
*/}
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button href="/" className="bg-green-400 w-mt hover:bg-green-500 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
value={selectedSection.section}
onChange={() => handleOnChange("section", QuickLinks)}
type="submit"
>Add Section</button>
</td>
</tr>
{console.log("Selected section", selectedSection.section)}
{/* ----------------------------Item List END COPY------------------------ */}
</tbody>
</table>
<div className="flex items-center justify-between">
<div className="block mt-5 bg-red-400 w-full hover:bg-red-500 text-white font-bold py-2 px-4 rounded focus:text-gray-600 focus:shadow-outline">
<Link to="/">Cancel</Link>
</div>
</div>
</form>
</div>
</React.Fragment>
);
};
Try using onClick instead of onChange for the button. I think onChange is for <input> tags not buttons. Also href is for links, not buttons. Unless this button is in a form type=submit isn't necessary. Also an arrow function isn't required for onClick. onChange={() => handleOnChange("section", QuickLinks)} -> onClick={handleOnChange("section", QuickLinks)}.

React - Hide parent's child element on blur event

I'm working on a custom input component. so when user clicks on the input element I want to show a dropdown that will contain default ten records and if user types some keyword in the input the dropdown will be updated with the results matching the keyword.
when user clicks on the input I want to show the dropdown and If they click out the container I want to hide the dropdown.
so I've added an onBlur event to the container and now if I click somewhere else it hides the dropdown but If I try to select a record It's also hidding the dropdown which is incorrect.
How can I hide the dropdown when the clicks outside of the input container? any suggestions?
export const ListBoxInput = ({ label, data, keyName }) => {
const [selected, setSelected] = useState({ key: null, value: null });
const [showDropdown, setShowDropdown] = useState(false);
return (
<div
className='flex items-center space-x-3'
onBlur={() => setShowDropdown(false)}
>
<label className='block text-sm font-medium text-gray-700'>{label}</label>
<div className='relative group'>
<input
type='text'
value={selected.key}
onFocus={() => setShowDropdown(true)}
onChange={(e) => setSelected({ key: e.target.value, value: null })}
disabled={!data.length}
placeholder={!data.length ? 'No data...' : ''}
className='w-full py-2 pl-3 pr-10 mt-1 text-left bg-white border border-gray-300 rounded-md shadow-sm disabled:opacity-50 focus:outline-none focus:ring-1 focus:ring-brand focus:border-brand sm:text-sm'
/>
{showDropdown && (
<div className='absolute z-10 w-full py-1 mt-3 overflow-auto text-base bg-white rounded-md shadow-lg max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none '>
{data.map((r) => (
<button
key={r.id}
type='button'
onClick={() => {
setSelected({ key: r[keyName], value: r.id });
setShowDropdown(false);
}}
className='block w-full py-2 pl-3 text-left hover:bg-gray-100 pr-9'
>
{r[keyName]}
</button>
))}
</div>
)}
</div>
</div>
);
};

Categories