I have a dropdown that is controlled via state.
Clicking on a button toggles it on. Clicking outside toggles it off.
The dropdown contains Links within my application, however, when the dropdown is being toggled off, route transition is prevented.
If autohide is disabled, routing works fine, however, it is desired to also hide the dropdown on route transition.
Please explain to me what is going on
Also please help me fix it
class App extends React.Component {
state = {
isNavShown: false
}
showNav = () => this.setState({isNavShown: true})
hideNav = event => {
// ... some more logic ...
// don't hide if autoHide is disabled
if (autoHide.checked === false) return
this.setState({isNavShown: false})
}
componentDidMount() {
document.addEventListener('mousedown', this.hideNav)
}
// ...
}
I have also tried wrapping the setState in setTimeout, but to no avail.
Here is the full jsfiddle https://jsfiddle.net/nimareq/1kh47uey/
So the issue is that your hideNav function is hiding the nav if the user clicks anywhere outside of show navigation button and the checkbox you built. However, if the user clicks on the nav itself it will be hidden before you have a chance to navigate the user.
Essentially, the browser will detect the click event listener you made on the document before it bubbles down to the anchor tag click. By the time it gets there the anchor tag is gone. (I hope that makes sense lol)
Anyways you can easily solve it by adding the following to your hideNav function:
if(nav.contains(event.target)) return;
Also don't forget to add the id="nav" on your navbar or whatever else you want to call it. This way the navbar won't disappear when u click on the navbar. It will still disappear if you click off the navbar.
Related
I have been doing research on this for days and finally have decided to ask this on here. I am using react and material-ui's ClickAwayListener component. The idea is that I have a button, which toggles the this.state.showGridPopup to the opposite of whatever it is currently is. So if the user was to click it once, the grid popup should show, click it again, the popup should disappear. There is an handleShowGrid handler attached to the button that does this:
handleShowGrid = (event) => {
const { widgetButtonEl } = this.state;
const element = widgetButtonEl === null ? event.currentTarget : null;
console.log('In handleShowGrid!!!!!');
this.setState({
showWidget: !this.state.showWidget,
widgetButtonEl: element
});
}
All this works well. And toggles the popup to show when we click on the button attached to the handler.
<ButtonBase onClick={this.handleShowGrid}>Open Swap</ButtonBase>
The issue is when I add Material-UI's ClickAwayListener. The reason for adding this is to close the grid when a user clicks outside the grid. Here is the ClickAwayListener below:
<ClickAwayListener onClickAway={this.handleCloseWidget}>
<SurveyGrid />
</ClickAwayListener>
And the handleCloseWidget handler:
handleCloseGrid = (e) => {
console.log('In handleCloseWidget!!!!!');
this.setState({
showWidget: !this.state.showWidget,
widgetButtonEl: null
});
}
So now clicking outside grid is fine and closes the Grid. However, now, clicking on the button that should toggle the Grid being show (this.state.showWidget), causes the handleCloseGrid to fire. And then afterwards the handleShowGrid would fire. Is there anyway to not have the handleCloseGrid handler to fire? It seems like an issue with propagation and event bubbling. Have tried different things like e.stopPropagation() but to no avail.
I am using the TabView component from PrimeVue (Vue 3), and I want to stop the tab change if any changes are made by the user, the problem is that I don't know how. I've already tried passing the event and using preventDefault and stopPropagation but seems that it doesn't work and click event is still happening.
The procedure should be:
If any changes are made, user press the tab and a dialog appears.
If user clicks 'No', I should prevent the tab change and stop the click event
Here is the demo of what I'm trying to archive, should be simple https://codesandbox.io/s/aged-wave-yzl1k?file=/src/App.vue:0-1753
If a flag is true I want to show a confirm dialog and prevent the tab change if user dismiss it.
The component that I'm using for the TabView: https://primefaces.org/primevue/showcase/#/tabview
Thanks in advance,
From the docs it looks like that internally the component will first switch tabs and then emit "tab-click", which explains the issue you're seeing. The exception is if the tab is disabled, in which case it won't change tabs but will emit "tab-click".
It took a bit to figure out, but there is a way to get the functionality you need with only a small adjustment. It requires a change in your main.js as well as in your App.vue file.
// main.js
/*
* Put this after you import TabView.
* This will prevent automatic tab switching but still emits
* the event to your application.
*/
TabView.methods.onTabClick = function(event, i) {
this.$emit('tab-click', {
originalEvent: event,
index: i
});
}
// App.vue
const onTabClick = (event) => {
if (changes.value) {
confirm.require({
message:
"Are you sure that you want to leave this tab? You'll lose your changes",
icon: "fal fa-exclamation-triangle",
acceptLabel: "Yes",
rejectIcon: "No",
accept: () => {
alert("here we should allow tab change");
activeIndex.value = event.index; // manually set activeIndex
},
reject: () => {
alert("stop tab change");
},
});
}
};
These changes modify what the onTabClick library method to only emit the event, without automatically switching. Then in your app you can check the index property of the event to determine what should be set to active.
I have the following problem, in my web site build with nextJS and ReactJS with typescript I have products that are loaded when a button is clicked, when I click the button the items appeared and the button is scrolled down, which is the asked behavior, but when I scroll to the bottom of the page and I try to click the button the scroll remains on the same position and the items are loaded but cannot be seen, my logic is to use onFocus on the current button and when I click it to change the scroll to him, that will solve the problem when the user has scrolled down to the bottom of the page, that way it will not remain on the bottom but rather it will automatically scroll up to the button and will see the new items loaded.
The problem is that the logic to load the products are in a different component in which I am reusing the current button and right prop I am sending function to the onClick on the button. My question is how can I use onFocus. Does it has to be in the child component inside the function or in the button component. I tried to make it work on the Button component, but it doesn't work. So I am stuck for the last 4 hours and I really need a push. I would be glad if you could shine some enlargement
Here I will enter the function in the parent component for the onClick prop :
const handleLoadMoreProducts = () => {
if (!isSearchPage) {
const mappedBreadcrumbs: string[] = categoryData.breadcrumbs.map(
(crumb: BreadCrumItem) => crumb.name
);
gtmBreadcrumbTrack(mappedBreadcrumbs);
}
<LoadMoreProducts handleLoadMoreProducts={handleLoadMoreProducts} />
And here is the component that uses the Button:
interface LoadMoreProductsProps {
handleLoadMoreProducts?: (MouseEvent: React.MouseEvent<HTMLButtonElement>) => void;
Focus?: (MouseEvent: React.MouseEvent<HTMLButtonElement>) => void;
}
const LoadMoreProducts: FC<LoadMoreProductsProps> = ({ handleLoadMoreProducts }) => (
<div className="LoadMoreProducts">
<Button type="button" importance="ghost" onClick={handleLoadMoreProducts}>
Load more products
</Button>
</div>
);
I think what you want to do is to forward the ref of the element you are trying to focus in the Button component using React.forwardRef and combine it with the useImperativeHandle hook in order to gain the ability to trigger the focus with the ref outside of the Button component.
You could create a ref for the element you are trying to focus and call the focus() function for the ref on click.
More information regarding forwarding refs and the useImperativeHandle hook.
I want to know when the user starts the navigation to a new page by clicking in a link located inside my Flickity slider. I have attached the jQuery click event on the links, but when the user slides and click at the same time, the click event on the <a> is triggered but the navigation to the link adress does not occur.
Demo : http://codepen.io/anon/pen/GoapaY
. To reproduce the issue : click down on the link, then slide, then release your click : the event is triggered but the navigation to example.com have not occured.
Which event/trick can I use to know when the user actually navigate to the link adress ?
Answer obtained with this issue opened on Flickity's GitHub :
This is the intended behavior. This allows users to slide the gallery using any element on the page, links, buttons, etc. It lets click events propagate. There's additional logic so that static clicks do trigger a click on the element, and allow links to go through if no sliding occurred.
Flickity's staticClick event might be what you're looking for.
This solves the issue for me:
$el.on('dragStart.flickity', () => $el.find('.slide').css('pointer-events', 'none'));
$el.on('dragEnd.flickity', () => $el.find('.slide').css('pointer-events', 'all'));
I just disable pointer events on dragStart and reinstate them on dragEnd.
Ali Klein's solution worked for me.
I'm not using jQuery so here is the code I'm using
const carousel = document.querySelector('.carousel')
const flkty = new Flickity(carousel, {
// ...options
on: {
'dragStart': () => {
carousel.style.pointerEvents = 'none'
},
'dragEnd': () => {
carousel.style.pointerEvents = 'all'
}
}
})
I have modal popup with an overlay written in html / js, everything works fine but if a user tabs enough they can get to the underlying form fields / buttons. Is there any good way of preventing this?
This is a rough idea but I'm hoping to inspire ideas rather than tell you exactly how to do it. I'll use a combination of pseudocode and pseudo-jquery-code:
function showMymodaldExample() {
//Show modal dialog (mymodal) code goes here
//
//Then we bind an event
$(document).bind('mymodal.keydown', function(e) {
if ( currently focussed element is not a child of mymodal ) {
set the focus previous element
}
});
}
And then remember to unbind mymodal.keydown when you destroy/hide the dialog