Open hoangvuanduin opened 1 year ago
Hm, yes, I don't think there's a good way to do this now. I wonder what kind of APIs do other routing libs have for this.
As a workaround, you could try to hack into router.currentPageSignal
. For example, if you currently have something like:
div(
child <-- SplitRender(router.currentPageSignal)....
)
You could try replacing router.currentPageSignal
with something like:
{
var maybeLastPage: Option[Page] = None
router.currentPageSignal.map { nextPage =>
val actualNextPage = if (okToExit) nextPage else {
val prevPage = maybeLastPage.get
js.setTimeout(0){ router.pushState(prevPage) } // pretend that the user didn't press the back button - keeps the router's internal state consistent with this hack.
prevPage
}
maybeLastPage = Some(nextPage)
actualNextPage
}
}
Basically, we can't prevent the popState event, so we will prevent the propagation of that event into the rendering stage, sort of. This is incredibly hacky so I don't know how well it will work (e.g. you might want to filter out redundant events), but I don't think there is another way. onBeforeOnload will not be called unless you do a full page refresh, and the whole point of frontend routers like Waypoint is to avoid such refreshes.
Thanks for your suggestion, I can see that there is no way to prevent the popState event. Last time I tried something similar to this, but the problem with router.pushState is it will mess up the browser history when the user hits forward instead of back (popState fires for forward as well). I think if we can't prevent the popState event no matter what, can you support a function to undo the popState event when we call it manually? I mean something to replace router.pushState in your above code but still keep the browser history instead of pushing another state.
Indeed, this kind of hack can break the forward button, especially in more complex navigation sequences.
To fix this properly, I think we'd need to implement something like this. I haven't looked at it in detail yet. I think it's something along the lines of undoing the undesirable navigation post-factum. The trick is, to undo it, you need to know whether to issue a history.back() or history.forward() command, and for that, you need to know whether the user pressed the back button (in which case you need to call history.forward to undo it) or did some other kind of navigation (in which case you need to call history.back to undo it), and for that you need to add sequential indexes to page state sent to the history API. And, all of that would need to happen in the router, prior to these shenanigans being exposed to the rendering logic.
Ok I know the above is a rather incomprehensible word salad, it's mostly a hint for myself about where to pick up when I eventually get to this.
Thanks! I am awaiting for this.
Hi, I am using Waypoint, and my use case requires the browser shows up a warning message when the user navigates out of page. Normally, I would do it like this:
dom.windowEvents.onBeforeUnload.map(_.returnValue = "") --> Observer.empty
However, it does not work when I go back after calling Waypoint router pushState. This is because Waypoint does not unload dom elements, so onBeforeUnload does not trigger. I attempted to tweak popStateEvent, however, it was kinda tricky because when onPopState triggers, the browser history has already changed, so I have to manually undo the pop state when the user decides not to leave page.
Could you please consider some support for this use case?