Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updateQueryString doesn't work with shinylive #4153

Open
willgearty opened this issue Nov 8, 2024 · 3 comments
Open

updateQueryString doesn't work with shinylive #4153

willgearty opened this issue Nov 8, 2024 · 3 comments

Comments

@willgearty
Copy link

updateQueryString() (or session$updateQueryString) ultimately calls window.history.replaceState() or window.history.pushState(). However, when using shinylive the app is served as an iframe, so window in this case refers to the iframe, not the parent window. Therefore, neither of these calls works and updateQueryString() does nothing. I've found the following works instead:

shinyjs::runjs(paste0("window.parent.history.pushState(null, null, '", pushQueryString, "')"))

The MDN docs state that "If a window does not have a parent, its parent property is a reference to itself." Therefore. changing the typescript code to just use window.parent instead of window should fix this problem, regardless of whether you are using shinylive or not.

@willgearty
Copy link
Author

willgearty commented Nov 8, 2024

Relatedly, session$clientData$url_hash doesn't work with shinylive either because it is based on window.location.hash, which also doesn't work within an iframe. So an observer like this won't work with shinylive:

observeEvent(session$clientData$url_hash, {
  ...
})

Again, I believe changing the typescript code to use window.parent.location.hash should fix the problem.

@gadenbuie
Copy link
Member

Thanks for opening the issue and the suggestion. We've discussed this in posit-dev/r-shinylive#28 and have done some work in this direction in posit-dev/shinylive#79.

Therefore. changing the typescript code to just use window.parent instead of window should fix this problem, regardless of whether you are using shinylive or not.

Unfortunately, I doubt it'd be this easy. For example, this change would be likely to break behavior where an app inside an iframe is expecting to find query parameters from window and not the window.parent.

Another complication is that it's very hard to judge the impact of this kind of change. In these cases we tend toward cautiously evaluating the change from first principles, which means being convinced that the change is safe in all theoretical cases.

On more wrinkle. Shinylive is actually a good example of how query parameters can be tricky to untangle: Shinylive itself makes use of query parameters that should be separated from the app's parameters. Those query parameters aren't widely used, but it points at the fact that simply passing query and hash components from the parent window down to the iframe carries inherent ambiguity.

I appreciate you sharing your snippet of JavaScript. That certainly seems like a very good solution to the problem, especially when you're certain that doing so won't be affected by the parent page's state.

@willgearty
Copy link
Author

willgearty commented Nov 11, 2024

Ah, I should have known that you all are already discussing this! I never even thought about situations where multiple shinylive apps are present on the same page, so now I totally understand the apprehension to change this. I guess I'll just stick with the hacks I've developed for the time being.

Speaking of which, in case anyone else comes across this issue...the url_hash problem is a bit trickier to deal with since you can't retrieve the response of any javascript that is run using shinyjs::runjs. I ended up adding a hidden text input in the UI, then added some javascript to change the input whenever the page's hash changed:

$(function() {
  $(window.parent).on('hashchange', function (e) {
    $('#currentHash').val(window.parent.location.hash).change();
  });
});

Then you just need to add an observer for that input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants