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.
Related
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.
When user click a button there is a directive that catches this event and stops it. Then an modal is opened witch asks for user confirmation. If user confirms then I need to resume previously event.
How do I resume stopped event?
example:
markAsSeen($event) : void {
// pause whatever user wanted to click
$event.stopPropagation();
// open modal and ask user for confirmation
let modalInstance = this.modalService.openConfirmationModal();
// on modal close, if positive event continue whatever user clicked
modalInstance.onClose((response) => {
if(response) {
// this line should resume $event
$event.originalEvent(); // how to achieve this?
}
})
}
For me this is two different events, the first one is here to openModal but looks useless (why don't you just open a modal ?), the second one to confirm when the user clicked Confirm.
For me that's the easiest way : if you need the first event emitter, then only open the modal, the second one start the confirmation process if positive. The other way could be to add a "status" variable in your confirmation -1 for not started (= modal closed), 1 for positive confirmation, 0 in progress.
Finally to avoid user to click away, use something like
onClick(event) {
if (!this.element.nativeElement.contains(event.target)) {
closeModal(); // or not
}
}
Where event.target is the clicked target
Edit : onClick must be added to #Component
#Component({selector..., host: {
'(document:click)': 'onClick($event)',
}});
I have to hide same field on it's blur event.
Extjs 6 calls event delegation on component hide method.Event delegation revert focus to last field which had focus.
And, I don't want this revert focus. Is there any way I can stop event delegation while hiding elements in extjs ?
Event delegation comes with extjs 5 - Delegated Events and Gestures in Ext JS 5
Method using for hide - https://docs.sencha.com/extjs/6.0/6.0.1-classic/#!/api/Ext.Component-method-onHide
onHide() method from ExtJS source code - check revertFocus()
onHide: function(animateTarget, cb, scope) {
var me = this,
ghostPanel, fromSize, toBox;
if (!me.ariaStaticRoles[me.ariaRole]) {
me.ariaEl.dom.setAttribute('aria-hidden', true);
}
// Part of the Focusable mixin API.
// If we have focus now, move focus back to whatever had it before.
me.revertFocus(); // this revert focus making probelm
// Default to configured animate target if none passed
animateTarget = me.getAnimateTarget(animateTarget);
// Need to be able to ghost the Component
if (!me.ghost) {
animateTarget = null;
}
// If we're animating, kick off an animation of the ghost down to the target
if (animateTarget) {
toBox = {
x: animateTarget.getX(),
y: animateTarget.getY(),
width: animateTarget.dom.offsetWidth,
height: animateTarget.dom.offsetHeight
};
ghostPanel = me.ghost();
ghostPanel.el.stopAnimation();
fromSize = me.getSize();
ghostPanel.el.animate({
to: toBox,
listeners: {
afteranimate: function() {
delete ghostPanel.componentLayout.lastComponentSize;
ghostPanel.el.hide();
ghostPanel.setHiddenState(true);
ghostPanel.el.setSize(fromSize);
me.afterHide(cb, scope);
}
}
});
}
me.el.hide();
if (!animateTarget) {
me.afterHide(cb, scope);
}
},
You are doing it wrong, revertFocus() is a main problem source. The solution might be:
blurEventFunction:function(cmp){
cmp.previousFocus = null;
cmp.hide();
}
Use suspendEvents and resumeEvents in the function you are calling in the viewcontroller when the blur event fires:
It's not stopEvents is suspendEvents. My fault. :P
blurEventFunction:function(cmp){
cmp.suspendEvents();
cmp.hide();
camp.resumeEvents();
}
I got the same problem. (extjs 6.5.1 - using a modal window with closeAction: 'hide')
I was debugging the code and seems it happened because the latest field focused was in a panel and my modal window was not child of that panel.
(seems the extjs get the ancestor of the modal window to find the latest focused field, then, set the focus)
When I added the window to that panel, it worked fine. (when the modal window was closed, the focus was on the latest field focused before open the window).
Debugging the Ext.util.Focusable class, I saw a config called preventRefocus. If you add that config with value true to your modal window, the content of the revertFocus function won't be executed and you won't get the error.
revertFocus: function() {
var me = this,
focusEvent = me.focusEnterEvent,
activeElement = Ext.Element.getActiveElement(),
focusTarget, fromComponent, reverted;
// If we have a record of where focus arrived from,
// and have not been told to avoid refocusing,
// and we contain the activeElement.
// Then, before hiding, restore focus to what was focused before we were focused.
// --->>> THE IF BELOW: !me.preventRefocus <<<---
if (focusEvent && !me.preventRefocus && me.el.contains(activeElement)) {
I hope it also can help somebody in the future.
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'
}
}
})
Im working with jquery mobile right now. And when the user clicks on the box, it will show an additional one. But when the user forced return on browser (or the backbutton), on that moment, the second box should hide, instead of going back the the prev page.
I've managed to achiev almost what I wanted with the popstate:
window.onpopstate = function(event) {
if($('div').is(':visible') {
closeFunction();
event.stopImmediatePropagation();
}
}
But it still changes the URL.
For example, if i has a nav like this:
index > home > internal(with box)
And then i pressed the back button
index > home
Will still trigger the url change, but not the page change.
I've tried with pagebeforechange, but with the same result.
Any ideas?
the popstate event is not cancellable.
referred doc
Specification: HTML5
Interface: PopStateEvent
Bubbles: Yes
Cancelable: No
Target: defaultView
Default Action: None