Accessing Python objects from Javascript

I want to make a string that is created in Python available in Javascript.

The flow is roughly:

  • a bunch of user-interactions take place in Python that result in a string (an ID); a bunch of Python libraries are involved here, and so I don’t think it’s easy to remove/rewrite this part of the process
  • a user then clicks a button that makes a request to an API to download data that is linked to this string/ID
  • this data can be quite large, and so I would like to download it directly to the user’s machine, rather than having it pass through the panel webserver
    -I want to pass this ID (generated at runtime) from Python to JS and I can’t do it!

Here’s some relevant code that I am using:

import panel as pn
import param

# I get an error in the browser saying 'target is not defined'
my_js_code = """
    let task_id = target.value;
    console.log(task_id);
"""

class MyTable(pn.viewable.Viewer):
    ... # param stuff    
    def __init__(self, ..., **params):
        self.task_id = pn.widgets.TextInput(name="Text Input", value="foo")
        self.my_button = pn.widgets.Button(name='my_button')
        self.my_button.js_on_click(args={"target": self.task_id}, code=my_js_code)        
        super().__init__(**params)

    def __panel__(self):
        # things to display like my_button

What do I need to change here to pass from Python to JS?

Bonus question: Is it possible (and how can I do it) to pass param objects to JS in a similar way eg param.String()?

Try pn_obj.jscallback(args={name_of_js_var: name_of_python_var})

I think what you have created already works?

import panel as pn

# I get an error in the browser saying 'target is not defined'
my_js_code = """
    let task_id = target.value;
    console.log(task_id);
    alert(task_id);
"""

class MyTable(pn.viewable.Viewer):
    def __init__(self, **params):
        
        self.task_id = pn.widgets.TextInput(name="Text Input", value="foo")
        self.my_button = pn.widgets.Button(name='my_button')
        self.my_button.js_on_click(args={"target": self.task_id}, code=my_js_code)        

        self._layout = pn.Column(self.task_id, self.my_button)
        
        super().__init__(**params)

    def __panel__(self):
        return self._layout

MyTable().servable()

Thanks Marc for the helpful response, and sorry for my delay in replying.

I went back and checked my original code. It turns out that I wasn’t passing self.task_id to be rendered by panel (ie it was missing from self._layout above), and I guess that meant it wasn’t getting ‘registered’ by param/panel.

(My language is a bit vague here because I’m still learning some of the concepts. But I think the important point for me was that I needed to have a variable rendered by panel if I wanted it available in JS land.)

Thanks ahuang11, and sorry for my slow response.

I think the issue was primarily user-error on my part - see my response to Marc.