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

rx.call_script: a real EventHandler to execute arbitrary javascript #1860

Merged
merged 1 commit into from
Sep 28, 2023

Conversation

masenf
Copy link
Collaborator

@masenf masenf commented Sep 24, 2023

The existing rx.client_side cannot be chained from a backend EventHandler since it is a BaseVar.

This new rx.call_script "server-triggered" event can be used to fire arbitrary js code on the page after performing backend processing without user intervention...and it can also be used in an event trigger (like on_click).

The main difference with rx.client_side is that we cannot access all args coming from the js trigger call, since those are handled by the get_event_triggers API. But now that get_event_triggers allows arbitrary arg mapping, this limitation does not matter as much.

Inspired by and Supersedes #1357
Fix #1346

Sample Code

pip install git+https://github.com/reflex-dev/reflex@masenf/call-script-event

(make sure to (re)run reflex init, since this contains changes to state.js)

import httpx

import reflex as rx


# load twitter.js https://developer.twitter.com/en/docs/twitter-for-websites/javascript-api/guides/set-up-twitter-for-websites
TWITTER_EMBED = rx.script("""window.twttr = (function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0], t = window.twttr || {}; if (d.getElementById(id)) return t; js = d.createElement(s); js.id = id; js.src = "https://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js, fjs); t._e = []; t.ready = function(f) { t._e.push(f); }; return t; }(document, "script", "twitter-wjs"));""")
TWITTER_EMBED_RELOAD = rx.call_script("window.setTimeout(window.twttr.widgets.load, 1)")


INTERESTING_TWEETS = [
    "https://twitter.com/pwang_szn/status/1617567945059872770",
    "https://twitter.com/elonmusk/status/1519480761749016577",
    "https://twitter.com/GretaThunberg/status/1608056944501178368",
    "https://twitter.com/BTS_twt/status/1353536893787357184",
    "https://twitter.com/IncredibleCulk/status/1298730289737293824",
]


class State(rx.State):
    tweet_url: str = ""
    tweet_html: str = ""

    def set_tweet_url(self, url: str):
        self.tweet_url = url
        if self.tweet_url:
            resp = httpx.get(
                f'https://publish.twitter.com/oembed?url={self.tweet_url}&hide_media=true&hide_thread=true&align=center&omit_script=true',
            )
            self.tweet_html = resp.json()['html']
        return TWITTER_EMBED_RELOAD


def post() -> rx.Component:
    return rx.center(rx.html(State.tweet_html))


def index() -> rx.Component:
    return rx.vstack(
        rx.heading("A Tweet For You..."),
        rx.select(
            rx.option("Select a tweet to embed", value=""),
            *[rx.option(tweet, value=tweet) for tweet in INTERESTING_TWEETS],
            value=State.tweet_url,
            on_change=State.set_tweet_url,
        ),
        post(),
    )


# Add state and page to the app.
app = rx.App()
app.add_page(index, script_tags=[TWITTER_EMBED])
app.compile()

rx.client_side cannot be chained from a backend EventHandler since it is a
BaseVar.

This new `rx.call_script` "server-triggered" event can be used to fire
arbitrary js code on the page after performing backend processing without user
intervention...and it can also be used in an event trigger (like on_click).

The main difference with `rx.client_side` is that we cannot access all args
coming from the js trigger call, since those are handled by the
`get_event_triggers` API. But now that `get_event_triggers` allows arbitrary
arg mapping, this limitation does not matter as much.

Inspired by and Supersedes #1357
Fix #1346
@picklelo picklelo merged commit 991c720 into main Sep 28, 2023
36 checks passed
@picklelo picklelo deleted the masenf/call-script-event branch October 9, 2023 21:07
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

Successfully merging this pull request may close these issues.

Set an event handler for a button so that it will call browser-side JavaScript code.
3 participants