Calendar component loses focus when I click on it - javascript

What I have achieved is when I click on the input field to show the Calendar component, and when I click outside of it to hide it. However, the problem is when I click on the icon (Calendar component) itself, I lose the focus, how to fix that? I do not want to lose the focus of the icon when I click on it.
const [isFocused, setIsFocused] = useState(false);
<form onSubmit={addTask}>
<div>
<input
id="task"
placeholder=' Add task to "Inbox" on "Tomorrow"'
className={styles.input}
onChange={handleChange}
value={taskName}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
></input>
{isFocused && <Calendar />}
</div>
Calendar component
const Calendar = () => {
const [isShown, setIsShown] = useState(false);
const clickIcon = (e) => {
e.preventDefault();
setIsShown((current) => !current);
};
return (
<div>
<CalendarMonthIcon
onClick={clickIcon}
className={styles.calendar}
></CalendarMonthIcon>
{isShown && <Datepicker />}
</div>
);
};
I currently can't stop the Calendar icon from losing the focus when click on it.

You loose the focus of your input, because the click on the icon triggers the onBlur function of the input. Therefor the input looses focus and the Calendar component is beeing closed.
By adding the following function to your onBlur event, it should check if there item pressed is a child element. If that's the case the input should remain focused and the Calendar should stay open.
IMPORTANT: you have to set that onBlur function on the parent div that includes the input and calendar, otherwise the function won't work, because it looks if the click contains a child. This is also a good way to keep track if the click was outside of your component.
const closeDropdown = (event) => {
if (!event.currentTarget.contains(event.relatedTarget)) {
setIsFocused(false);
}
}

Related

Focus on an input after div mounted Vue

When I click on a button the modal will show. The modal contains an input field. I want to set the focus to the input field inside the modal when the modal appears after clicking.
This is the button so when I click it the modal shows,
<div
class="manu-bar-card"
#click="
() => {
groupHandler.addNewgroupModal = true;
newGroupName.focus();
}"
>
This is my modal (This will show if groupHandler.addNewgroupModal is true),
<div class="modal-container" v-if="groupHandler.addNewgroupModal">
<input
ref="newGroupName"
type="text"
/>
</div>
This is the input field inside the modal I have set a ref attribute to it,
<input
ref="newGroupName"
type="text"
/>
I have registered that ref inside my <script setup> and the reactive object to show/hide modal,
const newGroupName = ref();
const groupHandler = reactive({
addNewgroupModal: false,
});
I think the reason for not focusing on the input field is modal is not mounted yet when the focus method is called. How to handle such a thing. Appreciate it if somebody could help. Thanks
Your modal should be a separate component.
Let's call it <Modal v-if="groupHandler.addNewgroupModal" />
Inside the Modal component, You can make a ref for your input, and in the onMounted function, you can call newGroupName.value.focus()
If you don't want to separate the modal to a saperate component for some reason.
You can use nextTick
<div
class="manu-bar-card"
#click="clickHandler"
>
And in the setup script.
<div
class="manu-bar-card"
#click="
() => {
groupHandler.addNewgroupModal = true;
newGroupName.focus();
}"
>
And in your setup script.
import { nextTick } from 'vue'
const clickHandler = async () => {
groupHandler.addNewgroupModal = true;
await nextTick()
newGroupName.value.focus();
}

facing quite strange issue in popup closing in react. method is getting called but popup is not closing

I have created one component. in which I have a button in which once you click popup will be displayed.
data for that popup is put in another component. below is the popup.
the problem is once I am clicking on the cross(x) button at corner my popuup is not getting closed.
below is the code to launch popup.
const [statusUpdateFlag, setStatusUpdateFlag] = useState(false);
<td>
<button type="button" onClick={(event) => handleStatusUpdateClick(event)}>
click
{statusUpdateFlag && (
<StatusUpdate
certificate={props.certificate}
handleStatusUpdateClick={handleStatusUpdateClick}
closePopUp={closePopUp}
/>
)}
</button>
</td>
once user click on the button , statusUpdateFlag will be true popup will be launched.
const handleStatusUpdateClick = async (event: SyntheticEvent) => {
event.preventDefault();
setStatusUpdateFlag(true);
}
now on the close button I have just made setStatusUpdateFlag(false); . even this method is getting called. still popup is not closing.
const closePopUp = (event: any) => {
alert("closepopup called");
event.preventDefault();
setStatusUpdateFlag(false);
};
once I click X method is getting called but popup is not closing.
below is code for X button,
<button
className={styles.closeicon}
onClick={(event) => props.closePopUp(event)}
>
x
</button>
what mistake I am doing?
You have written the Popup component as children of your button, so when you click on popup close, a trigger for parent button click is also triggered so popup visible state is again set true.
const [statusUpdateFlag, setStatusUpdateFlag] = useState(false);
<td>
<button type="button" onClick={(event) => handleStatusUpdateClick(event)}>
click
{/* Issue is here */}
{statusUpdateFlag && (
<StatusUpdate
certificate={props.certificate}
handleStatusUpdateClick={handleStatusUpdateClick}
closePopUp={closePopUp}
/>
)}
</button>
</td>;
You should bring out the StatusUpdate component outside button and in my opinion for UI, outside the whole table component if possible. That should fix the issue.

onClick handler in React is triggered by adjacent element , not by element which it was meant to trigger

const ProductScreen = () => {
const [qty, setQty] = useState(0);
const handleAddtoCart = () => {
console.log(qty);
};
return (
<div className="productScreen">
{product.countInStock > 0 && (
<div className="productScreen__details__qty">
<span>Qty : </span>
<select
id="qty"
name="qty"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</select>
</div>
)}
{product.countInStock > 0 ? (
<div className="productScreen__details__price__details__cart">
<button
className="productScreen__details__price__details__toCart"
onClick={handleAddtoCart()}
>
Add to Cart
</button>
</div>
</div>
</div>
);
};
Here handleAddtoCart gets triggered when selecting options but doesnt trigger when button is pressed(handleAddtoCart is added to button), when I change handleAddtoCart() to handleAddtoCart in onClick attribute of button it works properly.
Why when handleAddtoCart() is given as onclick attribute it is getting triggered by adjacent select option and is not getting triggered when button is pressed
You need to make a callback to that function, because every render of the component, will literally execute handleAddtoCart() and not as you expect it to happen only of the onClick trigger.
as react's Offical documents explained:
To save typing and avoid the confusing behavior of this, we will use the arrow function syntax for event handlers here and further below:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => console.log('click')}>
{this.props.value}
</button>
);
}
}
Notice how with onClick={() => console.log('click')}, we’re passing a function as the onClick prop. React will only call this function after a click. Forgetting () => and writing onClick={console.log('click')} is a common mistake, and would fire every time the component re-renders.
for more details:
https://reactjs.org/tutorial/tutorial.html
Change
onClick={handleAddtoCart()}
by
onClick={handleAddtoCart}
Also try with :
onChange={(e) => setQty(e.currentTarget.value)}
instead of :
onChange={(e) => setQty(e.target.value)}
The currentTarget read-only property of the Event interface identifies
the current target for the event, as the event traverses the DOM. It
always refers to the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

How to run onClick before onBlur takes place?

I have this tricky problem:
I have a text input field and a ul tag with a list of suggestions which when pressed should populate that input field.
export default function SimpleDemo() {
const [show, setShow] = useState(false)
const [text, setText] = useState("")
const updateText = (new_text) => {
setText(new_text)
setShow(false)
}
return (
<>
<input
type="text"
value={text}
onChange={(e) => { setText(e.target.value) }}
onClick={() => { setShow(true) }}
onBlur={() => { setShow(false) }} // because of this my updateText() handler never runs
/>
{show && (
<ul>
<li onClick={() => { updateText("Some Text") }}>Some Text</li>
<li onClick={() => { updateText("Suggestion 2") }}>Suggestion 2</li>
<li onClick={() => { updateText("Hello World") }}>Hello World</li>
</ul>
)}
</>
)
}
It works as expected until I add onBlur handler to my input field. (because I don't need to show suggestions when I'm not in that field)
When I add onBlur to my text input, my li tag onClick handler updateText(); never runs, thus never populating my input. They don't run because my ul tag gets deleted first thus there are no li tag elements with onClick handlers that could be clicked.
The only hack I found so far is wrapping contents of my onBlur in a setTimeout() with an arbitrary timeout duration. But it proved to be unreliable with a small timeout, and a high timeout makes it seem laggy on the front end.
Whats a reliable solution?
I'm trying to clone HTML datalist tag functuanality (because it lets me style it).
Replace your onClick handlers with onMouseDown. They fire before the blur event.

react toggle listen to other node of html

I'm doing a calendar component where the calendar will be closed if the user click on other places. The logic is dead simple, just hide and show using setState on the input to show the calendar. But how do I hide the calendar when user click on elsewhere of the screen?
If it's jquery I can use this logic.
$('calendar_input').click(function(){
if($(this).not('.calendar')) && !$(this).hasClass(.calendar_input)){
//close calendar
}
})
but how about react?
You can set and event listener on the input
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
console.log('You clicked outside of input!');
}
}
render() {
return (
<div ref={this.setWrapperRef}>
<input type="text" ref={(ip) => {this.wrapperRef = ip}}/>
</div>
);
}
i usually using this logic (sorry for my bad english) : Listen for event click and check target is child of "calendar".
In componentWillMount i add event click
window.onclick = (event) => {
if(!this.refs.calendar.contains(event.target)){
//set state close calendar
}}

Categories