I'm using Angular dragula drag and drop, which allow me to move bootstrap cards all around the view.
When you "drop" some item, it triggered this.dragulaService.drop.subscribe(), inside that I can cancel or roll back item dragged before the move is done.
I want to use my modal in there. which looks like this :
let subscription = this.modalService.onSubmit.subscribe((val) => {
That modal subscription keep thread waiting for user clicking on OK or CANCEL in modal, which says "Are you sure you want to move this item?"
The problem, is that otter event subscription (dragula) does not wait for modal event subscription to finish, dragula just ends before modal confirmation and it's a problem for me. Because when I try to call drake.cancel, it does not exist any more.
CODE :
this.dragulaService.drop.subscribe(
value => {
let modal: ModalComponent = this.modalService.GetModal();
let subscription = this.modalService.onSubmit.subscribe((val) => {
//Here if user clicks OK, we do nothing and drag-drop finish successfuly
//If user clicks Cancel, we call this.dragulaService.find('bag-deals').drake.cancel(true);
You can use a concatMap in a pipe, here is an interesting article about Higher-Order RxJS Mapping Operators
I used it in your case in that way:
let dropValue;
this.dragulaService.drop
.pipe(concatMap(value => {
dropValue = value;
const modal: ModalComponent = this.modalService.GetModal();
return this.modalService.onSubmit;
})).subscribe(value => {
//Here if user clicks OK, we do nothing and drag-drop finish successfuly
//If user clicks Cancel, we call this.dragulaService.find('bag-deals').drake.cancel(true);
});
Related
I have a component that allows a user to edit their state. This triggers a notSaved variable. I have a beforeunload event handler to handle reload and exiting the page to remind the user to save their state, but using SvelteKit, using the back button in the browser doesn't seem to trigger the beforeunload event. I also have a popstate event handler, because that is triggered when the back button is clicked, but I can't figure out how to prevent the window.history from changing if the notSaved variable is true.
Is there a way in SvelteKit to trigger a Changes you made may not be saved. popup similar to the one that is triggered on a beforeunload event when the back or forward button is pressed?
You can use the beforeNavigate function to be notified of a navigation intent in order to potentially block it, for example:
<script>
import { beforeNavigate } from '$app/navigation';
let unsavedWork = false;
let value = 0;
beforeNavigate(({ from, to, cancel }) => {
if (unsaved) {
cancel();
showUnsavedWorkPopup();
}
});
function onChange() {
...
unsavedWork = true;
}
async function save() {
await ...
unsavedWork = false;
}
</script>
<input type="number" bind:value on:change={onChange}>
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.
Is there any way to know if the dispatched action from a component has completed or not without setting a state?
Right now I have an action - createAddress
In my component, I have a modal where the user enters address.
When the user enters the details and clicks on 'Save' button, I dispatch the action like this -
saveAddress () {
this.$store.dispatch('createAddress', this.address)
}
The action makes an axios call and returns either status 200 OK or error.
If status 200 I want to close the modal. If error, I don't want to close it.
What is the best way to achieve this? Do I really have to create a state, update that state value, watch that value in the component and then close the modal?
Below is what I want from code point of view
saveAddress () {
this.$store.dispatch('createAddress', this.address)
// Close modal if success
}
saveAddress () {
this.$store.dispatch('createAddress', this.address, this)
}
and in createAddress, you can close modal
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 an issue with the back button running more than once.
currently I'm in my "messages" $state, and if I press the back button the following code works as normal.
var messageIsClosed = true;
$ionicPlatform.onHardwareBackButton(function(event){
event.stopPropagation();
handleBackButton();
})
var handleBackButton = function(){
if(messageIsClosed){
$state.go("dash");
} else {
messageIsClosed = false;
}
}
however, if I go to another $state (say, "dash") and then return to "messages", pressing the back button will make the above code run twice. Then if I go back to "messages" again it runs 3 times, then 4. For each time I visit the "messages" view/controller the back button code will run an extra time
I have no idea why
The onHardwareBackButton will run multiple times and this is normal in your case. This is because you are registering the event every time you visit the messages state.
To avoid the multiple registration of the event you could useoffHardwareBackButton() and de-register the event when moving away from the current state.
Example code:
This is the callback
var hardwareBackButtonHandler = function() {
// add you back button logic here
console.log('Hardware back button pressed');
}
Register the back button event like that:
$ionicPlatform.onHardwareBackButton(hardwareBackButtonHandler);
Then when moving away from the current state you can un-register like that:
$ionicPlatform.offHardwareBackButton(hardwareBackButtonHandler);