So i have this searchbar ,that when the user types any letter that's been contained in any of my articles,the div pops up and show the related articles,but then,unless i backspace,it offcourse stays there,so i would like it to dissapear after i clicked somewhere else.My project is in React,so i have found many solutions in vanilla JS but none of them seem to work,in my project at least
.autocom-box {
position: absolute;
right: 57vw;
margin-top: 1vh;
z-index: 9;
color: white;
background-color: rgb(41, 57, 85);
width: 25vw;
}
.autocom-box li {
width: 100%;
list-style: none;
display: flex;
cursor: pointer;
}
.autocom-box li :hover {
background-color: rgb(64, 89, 133)
}
.autocom-box li {
height: 8vh;
color: white;
text-decoration: none; /*removes underline*/
width: 75%;
font-size: 12px;
text-align: center;
padding-top: 3vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
export default function Header(){
const [articles,setArticles] = useState([])
const [search,setSearch] = useState('')
const [searchResults,setSearchResults] = useState([])
useEffect(()=>{
const results = articles.filter((article) =>
((article.title).toLowerCase()).includes(search.toLowerCase()));
setSearchResults(results);
},[articles,search])
const autocom = document.getElementById('autocom-box')
const hideOnClickOutside = (e) =>{
if (e.composedPath().includes(autocom)) {
alert('click insdide')
}else{
alert('click outside')
}
}
return(
<div className="search">
<form onSubmit={(e)=>{e.preventDefault();}}>
<input type="text" id="input" name="input" autoComplete='off' placeholder="Αναζήτηση..." value = {search} onChange={(e)=>{setSearch(e.target.value)}}/>
</form>
</div>
<div className="autocom-box" id="autocom-box" >
<ul onClick={hideOnClickOutside}>
{searchResults.map( (item,index)=>{
if (search.length>0){
return (<li> {item.title}</li>)
}
})}
</ul>
</div>
)
CodePudding user response:
Does this answer help you ?
const outsideClickListener = event => {
const deltaX = event.offsetX - lastMouseDownX;
const deltaY = event.offsetY - lastMouseDownY;
const distSq = (deltaX * deltaX) (deltaY * deltaY);
const isDrag = distSq > 3;
const isDragException = isDrag && !lastMouseDownWasOutside;
if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null
element.style.display = 'none';
removeClickListener();
document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener()
}
}
Cheers
CodePudding user response:
You can use this custom hook, to execute callback function when you click outside the target element.
Code with javascript
import { useEffect } from "react";
/**
* Hook that alerts clicks outside of the passed ref
*/
export default (ref, callbackFunc) => {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside({ target }) {
if (ref.current && !ref.current.contains(target)) {
callbackFunc()
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
Code with Typescript
import { useEffect, RefObject } from "react";
/**
* Hook that alerts clicks outside of the passed ref
*/
export default (ref: RefObject<HTMLElement>, callbackFunc: Function) => {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside({ target }: MouseEvent) {
if (ref.current && !ref.current.contains(target as Node)) {
callbackFunc()
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
The hook accept two parameters
- The element reference
- The callback function, which in your case inside you will set the state which depends on it you will hide the element.