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}
Related
I have an eventListener with a click event and want to trigger my function always but with two exceptions. This is my code (that works):
function setCookieTrueOnClick (event) {
if (event.target.pathname === '/info' || event.target.classList.contains('NoTrigger') ) {
} else {
triggerTheFunction('true');
}
}
window.addEventListener("click", setCookieTrueOnClick, false);
The event triggers always but not when the user click the box that has "NoTrigger" class or when the user clicks on a link that goes to /info.
Now, on the other hand, when I use a negative condition the code doesn't work (it triggers the function all the time):
function setCookieTrueOnClick (event) {
if (event.target.pathname !== '/info' || !event.target.classList.contains('NoTrigger') ) {
triggerTheFunction('true');
}
}
window.addEventListener("click", setCookieTrueOnClick, false);
I don't understand why, I also tried setting the eventListener with "true" argument, but it's always the same.
As #Prerak Sola commented, you have reversed the conditional checks but not the condition as a whole.
if(!event.target.pathname === '/info' && !event.target.classList.contains('NoTrigger'))
You will need to also inverse the || into and &&
.Try it out and let us know
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 })
}
}
}
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)
}
TL;DR;
Is there a way to force the focus to be inside a modal box in a web page ?
Here's the problem: I have a classic web page, containing text, links and forms. When I click one specific link in the page, a modal box appear (something similar to fancybox or jQuery.ui.dialog). This modal contains also links and form elements. If the user use its "tab" key, he can focus every element on the page, elements which are inside the modal, but also elements which are outside it. I would like to force the focus to say inside the modal box, but I can't find a way to do it. I would like to do this in CSS or JavaScript if possible.
I know this is possible, because jQuery.ui.dialog can do it using the modal option, here's an example http://jsfiddle.net/pomeh/QjLJk/1/show/. I tried to look at the source code but I'm not figuring how it works precisely. Here's some code I found in the jQuery UI source code which sounds like resolving this issue:
this.document.bind( "focusin.dialog", function( event ) {
if ( !that._allowInteraction( event ) ) {
event.preventDefault();
$(".ui-dialog:visible:last .ui-dialog-content")
.data( widgetFullName )._focusTabbable();
}
});
_allowInteraction: function( event ) {
if ( $( event.target ).closest(".ui-dialog").length ) {
return true;
}
// TODO: Remove hack when datepicker implements
// the .ui-front logic (#8989)
return !!$( event.target ).closest(".ui-datepicker").length;
},
_focusTabbable: function() {
// Set focus to the first match:
// 1. First element inside the dialog matching [autofocus]
// 2. Tabbable element inside the content element
// 3. Tabbable element inside the buttonpane
// 4. The close button
// 5. The dialog itself
var hasFocus = this.element.find("[autofocus]");
if ( !hasFocus.length ) {
hasFocus = this.element.find(":tabbable");
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogButtonPane.find(":tabbable");
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialog;
}
hasFocus.eq( 0 ).focus();
}
keydown: function( event ) {
if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
event.keyCode === $.ui.keyCode.ESCAPE ) {
event.preventDefault();
this.close( event );
return;
}
// prevent tabbing out of dialogs
if ( event.keyCode !== $.ui.keyCode.TAB ) {
return;
}
var tabbables = this.uiDialog.find(":tabbable"),
first = tabbables.filter(":first"),
last = tabbables.filter(":last");
if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
first.focus( 1 );
event.preventDefault();
} else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
last.focus( 1 );
event.preventDefault();
}
}
I wont get into the coding as you already have the code, I'll explain you the logic behind it.
If your page has the following elements,
element0(tabindex 1) --> element1(tabindex 2) --> element2(tabindex 3)
To prevent focus going out, you basically create a cycle.
When tab key is pressed on element0, it goes to element1 as it would normally go.
But when the tab key is pressed on element2, you need to prevent the browser's default behaviour (by event.preventDefault()) i.e going to an element with a higher tabindex and give focus to the element0.
Same ways when shift+ tab is pressed on element0, you need to prevent the browser's default behaviour (event.preventDefault()) and manually give focus to element2.
In this way, you create a cycle such that focus never goes outside.