My field onClick event toggles a dropdown, the onFocus event opens it.
When the onFocus event is fired the onClick event is fired afterwards and closes the newly opened dropdown.
How can I prevent firing on Click in Case onFocus fired?
preventDefault and stopPropagation do not work, both events are always fired
<TextInputV2
label={label}
onChange={handleInputOnChange}
onClick={handleOnClick}
onFocus={handleOnFocus}
onKeyUp={handleInputOnKeyUp}
readOnly={!searchable}
value={inputValue}
/>
.......
const handleOnFocus = (event: React.FocusEvent): void => {
if (!isOpen) {
changeIsOpen(true)
}
}
const handleOnClick = (event: React.SyntheticEvent): void => {
if (!searchable) {
toggleOpen()
}
}
My field onClick event toggles a dropdown, the onFocus event opens it.
When the onFocus event is fired the onClick event is fired afterwards and closes the newly opened dropdown.
How can I prevent firing on Click in Case onFocus fired?
preventDefault and stopPropagation do not work, both events are always fired
<TextInputV2
label={label}
onChange={handleInputOnChange}
onClick={handleOnClick}
onFocus={handleOnFocus}
onKeyUp={handleInputOnKeyUp}
readOnly={!searchable}
value={inputValue}
/>
.......
const handleOnFocus = (event: React.FocusEvent): void => {
if (!isOpen) {
changeIsOpen(true)
}
}
const handleOnClick = (event: React.SyntheticEvent): void => {
if (!searchable) {
toggleOpen()
}
}
Share
Improve this question
edited Sep 2, 2019 at 15:55
Brian Tompsett - 汤莱恩
5,89372 gold badges61 silver badges133 bronze badges
asked Sep 2, 2019 at 11:15
jeffjeff
1,1972 gold badges19 silver badges47 bronze badges
2
- is there any codepen available? – Harish Commented Sep 2, 2019 at 11:29
- The issue is that you don't stop event to be propagated. In case of the click both onClick and onFocus will be fired if you will not stop event propagation. See: stackoverflow./questions/282245/dom-event-precedence – Maciej Trojniarz Commented Sep 2, 2019 at 11:32
2 Answers
Reset to default 16You will want to change onClick
to onMouseDown
. Since event order is
- mousedown
- change (on focused input)
- blur (on focused element)
- focus
- mouseup
- click
- dblclick
from: this answer
You want to preventDefault/stoPropagation BEFORE the focus event, which means you have to use "onMouseDown" to properly stop it before the focus event get triggered.
In your case it would be:
<TextInputV2
label={label}
onChange={handleInputOnChange}
onMouseDown={handleOnClick}
onFocus={handleOnFocus}
onKeyUp={handleInputOnKeyUp}
readOnly={!searchable}
value={inputValue}
/>
const handleOnClick = (event) => {
event.preventDefault()
event.stopPropagation()
if (!searchable) {
toggleOpen()
}
}
https://jsfiddle/reactjs/69z2wepo/
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'hello'
}
this.lastFocus = 0;
}
handleOnClick(ev) {
const now = new Date().getTime();
console.log('diff since lastFocus');
console.log(now - this.lastFocus);
if (now - this.lastFocus < 200) {
return;
}
const newText = this.state.text + 'c';
this.setState({text:newText})
}
handleOnFocus(ev) {
this.lastFocus = new Date().getTime();
const newText = this.state.text + 'f';
this.setState({text:newText});
}
render() {
return <div>
<input name="" id="" cols="30" rows="10"
value={this.state.text}
onClick={this.handleOnClick.bind(this)}
onFocus={this.handleOnFocus.bind(this)}
></input>
</div>;
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
You store the time of your lastFocus -- not in this.state because that updates asynchronously and you cannot rely on that being updated in the onClick handler by calling setState in the onFocus handler. You put it directly on the instance and update it directly.
You can just use a rule of thumb that says if the last focus was within 200ms, then this onClick handler is from the same event as the onFocus handler, and therefore not run the rest of your onClick handler.
My fiddle is not obviously your entire use case, I'm just adding f on focus and c on click to the input text.