obsidiansystems / obelisk

Functional reactive web and mobile applications, with batteries included.
https://reflex-frp.org
BSD 3-Clause "New" or "Revised" License
954 stars 104 forks source link

Reloading the session #1051

Open walseb opened 11 months ago

walseb commented 11 months ago

Hello!

I handle the user clicking links by using the routing feature, however, on some pages I need to load in unstable Javascript that needs to be unloaded after the person leaves the page.

The way I dealt with it in the past was to simply link it as an HTML page, so as the user exited the page, the entire DOM and Javascript session would be reloaded. But now that I have converted it into Haskell, I link to it using an Obelisk route, and it doesn't flush the Javascript session between links.

How would I go about clearing the Javascript session to get rid of any bad code that I loaded in?

Thank you!

walseb commented 11 months ago

I looked around some more, and doing this solves my problem:

enc <- askRouteToUrl
elAttr "a" ("href" =: enc route) $ do

This is because linking to the page using a href causes the browser to discard the current page after clicking it, preventing the routing from keeping the JavaScript state.

Does anyone know of a nicer way to do this? Ideally, using the Obelisk routing facilities. Maybe you can specify that the page should be entirely reloaded after routing somehow?

walseb commented 11 months ago

Unfortunately, using href doesn't work on Android, so I need to find another solution. Href works for html files in the static directory, but not for routes.

I get the error:

Webpage not available
The webpage at https://appassets.androidplatform.net/URL could not be loaded because:

net::ERR_NAME_NOT_RESOLVED

When I try to click that link.

walseb commented 11 months ago

This restriction also seems to apply to ID href links. That is, href links like this: "#main". Those links give me the same error.

walseb commented 11 months ago

I solved it in an ugly way using JavaScript by putting this in my head:

  inlineJs ("type" =: "text/javascript") "if (typeof mySwitchTimes === 'undefined') {var mySwitchTimes = 0;}"

and this inside my routing function, so that it's called whenever the page is re-routed.

  inlineJs ("type" =: "text/javascript") "mySwitchTimes += 1;"
  inlineJs ("type" =: "text/javascript") "if (mySwitchTimes > 1 && !(typeof VARIABLE-THAT'S-IN-BAD-JAVASCRIPT === 'undefined')) { location.reload() };

The mySwitchTimes makes sure it doesn't get stuck in an infinite loop refreshing the page.

inlineJs is simply a wrapper like this:

inlineJs :: DomBuilder t m => Map Text Text -> Text -> m ()
inlineJs attrs code = elAttr "script" attrs $ text code
walseb commented 11 months ago

One Android compilation later, and it turns out I declared victory too soon, reloading it using location.reload doesn't work either, and gives me the same address not found error as clicking a href link.

I'm out of ideas, it looks like I will just have to write some Javascript to clean up after the bad Javascript I'm loading.