I have a React Modal that opens and closes via a handler function.
I'd like to call that function with either a click event or with the use of the esc key for accessibility proposes.
How could I track both events at the same time?
So far I got the esc event as:
handleCloseModal = event => {
if (event.keyCode === 27) {
this.setState({ modal: false })
}
}
But then I lose the click functionality on
<Modal
onClick={handleCloseModal}
role="button" tabIndex={0}
onKeyDown={handleCloseModal}
/>
How should I go about this?
One possible solution can be: Create a separate function to close the Modal. Use that function for onClick and call it when esc key pressed.
Like this:
<Modal
onClick={handleCloseModal}
role="button" tabIndex={0}
onKeyDown={handleKeyDown}
/>
handleKeyDown = event => {
if (event.keyCode === 27) {
handleCloseModal()
}
}
handleCloseModal = () => this.setState({ modal: false })
If I understand correctly, you're wanting to reuse the same close event handler for both click and keydown event types. One way to distinguish between these two event types would be to detect the event object's type via instanceof as follows:
handleCloseModal = event => {
// if event is mouse event, handle it accordingly
if(event instanceof MouseEvent) {
// if mouse click detected hide the modal
this.setState({ modal: false })
}
// if event is keyboard event, handle it accordingly
else if(event instanceof KeyboardEvent) {
// if escape key pressed for keyboard event then hide the modal
if (event.keyCode === 27) {
this.setState({ modal: false })
}
}
}
Related
I have developing an application that records the events and replays them. For that I need to identify what kind of event is being generated because mouse, keyboard and form events behave differently from each other.
Right now i am trying to use:
e instanceof KeyboardEvent but this doesn't seems to be working. What is the better way of identifying to which event family it belongs to?
A basic example for a mouse and keyboard event. You just have to add an eventListener to your desired dom element. And then you have to check if the triggered event e is an instance of MouseEvent or if it is a KeyboardEvent.
const button = document.getElementById('mouse');
button.addEventListener('mousedown', (e) => {
if (e instanceof MouseEvent) {
console.log('a mouse event');
}
});
const inputField = document.getElementById('keyboard');
inputField.addEventListener('keydown', (e) => {
if (e instanceof KeyboardEvent) {
console.log('a keyboard event');
}
});
<button id="mouse">MouseButton</button>
<input id="keyboard">
Using the event.detail allow you to determine if the event was a keypress or mouse event
if (event.detail === 0) {
// keypress event
} else {
// mouse event
}
Read more here - https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail
I have a div that has subscription for both onClick and onKeyPress (Enter click).
the desired behaviour for mouse click is: first click - open popup, second click - close popup.
the desired behaviour for enter click is: open popup.
when tabbing the focus to the div and click enter the subscribed method is fired twice, and it needs to be fired only once.
since, the same function is called twice on enter click, it opens and closes the popup.
i tried the followings:
subscribe to keyUp/keyDown instead of onKeyPress.
checking, in the onClick subscription if the event.detail === 0, but it was 0, when enter clicked also.
in onClick, checking if the event.type === 'mousedown', but it was always equal to 'click'
subscribe to onMouseDown/Up instead of onClick, the enter clicked stopped working.
this is the component firing the event
const eventPressHandler = e => {
if (e.key === 'Enter') {
return handleEventClick(e, true);
}
if (e.key === 'Tab' || (e.shiftKey && e.key === 'Tab')) {
return closeExpanded();
}
}
return (
<>
<div
onClick={handleEventClick}
onKeyPress={eventPressHandler}
className={st(
classes.root,
{ isAllDay, isInPopper, isMultiDay, isMobile, isAgenda, isCut, isWeekend },
className
)}
>
{event}
</div>
{popper}
</>
)
};
this is the handler in the parent component:
const handleEventClick = (eventElement, isKeyClicked) => {
isKeyClicked && setIsEventEventEntered(true);
setExpanded(
expanded || type === EventTypes.ShowMore ?
null :
eventElement.currentTarget,
() => {
onEventExpanded && onEventExpanded(expandedData) // i use custom hook to fire functions after the setState
}
);
}
I looked in a lot of similar issues but none of them had solution that worked for me.
i solved it like this:
onClick={e => e.detail === 1 && handleEventClick(e) }
onKeyUp={eventPressHandler}
I want to handle mouse right-click event for my button. I wrote the following code;
mybutton.onmousedown = e => {
e.preventDefault();
const mouseEvent = {
0: () => leftClickCallback,
2: () => rightClickCallback
}
mouseEvent[ e.button ]();
}
It works fine but it doesn't prevent the browser context menu and I have to set the "oncontextmenu" event like below to prevent the browser context menu event;
mybutton.oncontextmenu = e => e.preventDefault();
I've also tried to stop propagation of mouse event like below although it didn't work:
mybutton.onmousedown = e => {
e.preventDefault();
e.stopPropagation(); // <====
const mouseEvent = {
0: () => leftClickCallback,
2: () => rightClickCallback
}
mouseEvent[ e.button ]();
}
I am wondring why I need to explicitly disable oncontextmenu event for my button.
The right mouse button click seems to fire multiple events (though it might depend on the browser) :
a MouseDown event, with event.button === 2 and/or event.which === 3,
a ContextMenu event.
It makes sense since the context menu can also be opened by a keyboard button (depending on your keyboard layout), or a macro.
What you can do is use the same callback. For example :
function preventAll(event) {
event.preventDefault();
event.stopPropagation();
}
document.getElementById('something').addEventListener('mousedown', preventAll);
document.getElementById('something').addEventListener('contextmenu', preventAll);
<button id="something">test</button>
let's say I have a function that gets executed on key press that looks like something like this. I want to have special case for when Enter is pressed otherwise I want even to propogate/bubble up to the browser. Therefore, if any other key is pressed this i.e up or down arrows they should work.
onAutosuggestInputKeyDown = event => {
if (event.key === 'Enter') {
this.onCustomSuggestionCreate(event)
} else {
// keep propgating the event
}
}
getAutosuggestInputProps = () => {
return {
inputProps: {
onBlur: this.onCustomSuggestionCreate,
onKeyDown: this.onAutosuggestInputKeyDown,
},
}
}
<ReactAutoSuggest textFieldProps={this.getAutosuggestInputProps()}/>
If I understand your situation correctly, then even propagation should occour by default (depending on the type of element that fired the event).
You would however, likely want to use stopPropagation() in the case of the enter key being pressed to prevent the propagation of that event, which would be achieved by the following update to your onAutosuggestInputKeyDown method:
onAutosuggestInputKeyDown = event => {
if (event.key === 'Enter') {
// Prevent this event from propagating if enter key pressed
event.stopPropagation()
this.onCustomSuggestionCreate(event)
}
// If stopPropagation() not called on event, the event will propagate
// if it has the ability to do so (ie from the element dispatching the
// event)
}
I know that the keyboard menu key is keyCode === 93.
So I have the following code:
$(window).on("keydown", document, function(event){
if (event.keyCode === 93) { //context menu
console.log("context menu key", event);
event.preventDefault();
event.stopPropagation();
return false;
}
});
Although the event does fire, and the console does get logged inside the if statement, but the context menu still shows even though both event.preventDefault(); and event.stopPropagation(); are present in my code.
Is there any way to prevent the menu from being displayed?
Demo for fiddling: http://jsfiddle.net/maniator/XJtpc/
For those of you who do not know what the "menu" key is:
This is kind of dumb but it seems to work: http://jsfiddle.net/XJtpc/2/ :)
$(function(){
var lastKey=0;
$(window).on("keydown", document, function(event){
lastKey = event.keyCode;
});
$(window).on("contextmenu", document, function(event){
if (lastKey === 93){
lastKey=0;
event.preventDefault();
event.stopPropagation();
return false;
}
});
});
I started with #aquinas' solution but discovered it can be a bit simpler than that.
Steps
Register keydown event handler. e.preventDefault not required.
Register contextmenu event handler and just do e.preventDefault()
Example:
// JavaScript
// Register your `ContextMenu` key event handler
document.querySelector('body').onkeydown = (e) => {
if (e.key === 'ContextMenu') {
// Do something
}
}
// Prevent `contextmenu` event default action
document.querySelector('body').oncontextmenu = (e) => e.preventDefault();
// jQuery
// Register your `ContextMenu` key event handler
$('body').on('keydown', (e) => {
if (e.key === 'ContextMenu') {
// Do something
}
});
// Prevent `contextmenu` event default action
$('body').on('contextmenu', (e) => e.preventDefault());
The trick is that it's the keyup event, not the keydown event that triggers the context menu. Calling .preventDefault() on a keyup event whose .key is ContextMenu will stop it from happening, at least in Chrome and Electron.
That is, you can globally disable the context menu key just with:
window.addEventListener("keyup", function(event){
if (event.key === "ContextMenu") event.preventDefault();
}, {capture: true})
And then monitor the keydown event to trigger your replacement.