Close dialog/bottomSheet when clicking browser back?
-
Is there a way of closing dialog or bottom sheet when a user clicks the back button (desktop and mobile browser)?
Currently I’m doing this:
boot file
Vue.prototype.$a = { bottomSheet: function(opt) { const self = opt.parent; const sheet = BottomSheet.create(opt).onDismiss(() => { self.$router.history.stack[self.$router.history.index].params.$dialog = null; }); self.$router.history.stack[self.$router.history.index].params.$dialog = sheet; return sheet; }, dialog: function(opt) { const self = opt.parent; const dialog = Dialog.create(opt).onDismiss(() => { self.$router.history.stack[self.$router.history.index].params.$dialog = null; }); self.$router.history.stack[self.$router.history.index].params.$dialog = dialog; return dialog; } };
router file
Router.beforeEach((to, from, next) => { // close any open dialog const dialog = get(from, "params.$dialog", false); if (!!dialog) { dialog.hide(); } }
But this has its downsides:
- It won’t work if there’s no going back (stack is 1)
- It will go back a route not just close the dialog
-
@codebreaker dialog has a hide method.
... data dialog: null .... methods someFunc this.dialog = this.$q.dialog... ... beforeDestroy ... this.dialog.hide()
-
That is correct and I am using it to close the dialog in router file. Although, I did complicate it a lot.
In the end, this does not solve the main two problems:
- It won’t work if the parent component won’t be destroyed
- It will go back a route not just close the dialog
I have improved upon my previous attempt that solve these issues:
boot file
function dialogHideLogic(dialog) { const hideDialog = () => dialog.hide(); // listen for browser back button window.addEventListener("popstate", hideDialog); // add to current state a signal so that the router change routes window.history.replaceState({ ...window.history.state, freeze: true }, "", window.location.href); // add new state so that the back button will not go to previous route window.history.pushState({}, "", window.location.href); return dialog.onDismiss(() => { window.removeEventListener("popstate", hideDialog); // if hide isn't called by popstate event, go back one step to remove the freeze step if (!get(window.history.state, "popstate", false)) window.history.back(); }); } export default () => { Vue.prototype.$a = { bottomSheet: function(opt) { return dialogHideLogic(BottomSheet.create(opt)); }, dialog: function(opt) { return dialogHideLogic(Dialog.create(opt)); } }; };
router file
// hook into browser back button window.addEventListener("popstate", function(event) { if (get(event.state, "freeze", false)) { // clear freeze so that we can call this route again when user uses the browser back window.history.replaceState({ ...window.history.state, freeze: false }, "", window.location.href); } else { Router.back(); } // don't allow user to go back since we can't handle browser forward (no event) window.history.pushState({ popstate: true }, "", window.location.href); });
It’s a bit of a hack, but it works.
Note: I am using abstract routing so that why I can do this. I don’t know if it can be done in other modes.
-
A few bug fixes later:
boot file
function dialogHideLogic(dialog) { const hideDialog = () => dialog.hide(); // listen for browser back button window.addEventListener("popstate", hideDialog, { once: true }); // append to current state a signal so that the vue router does not go back it's history stack window.history.replaceState({ ...window.history.state, freeze: true }, "", window.location.href); // push new state so when back button is pressed, window.history.state contains the freeze property window.history.pushState({ ...window.history.state, freeze: false }, "", window.location.href); return dialog.onDismiss(() => { // remove popstate listener window.removeEventListener("popstate", hideDialog); // push a fresh state onto history stack window.history.pushState({}, "", window.location.href); }); } export default () => { Vue.prototype.$a = { bottomSheet: function(opt) { return dialogHideLogic(BottomSheet.create(opt)); }, dialog: function(opt) { return dialogHideLogic(Dialog.create(opt)); } }; };
router file
// hook into browser back button window.addEventListener("popstate", function(event) { if (!get(event.state, "freeze", false)) { Router.back(); } // don't allow user to go back since we can't handle browser forward (no event, not that we want to) window.history.pushState({ popstate: true }, "", window.location.href); });