|
| 1 | +# Event handlers in PyScript |
| 2 | + |
| 3 | +PyScript offer two ways to subscribe to Javascript event handlers: |
| 4 | + |
| 5 | +## Subscribe to event with `py-*` attributes |
| 6 | + |
| 7 | +The value of the attribute contains python code which will be executed when the event is fired. A very common pattern is to call a function which does further work, for example: |
| 8 | + |
| 9 | +```html |
| 10 | +<button id="noParam" py-click="say_hello_no_param()"> |
| 11 | + No Event - No Params py-click |
| 12 | +</button> |
| 13 | +<button id="withParam" py-click="say_hello_with_param('World')"> |
| 14 | + No Event - With Params py-click |
| 15 | +</button> |
| 16 | +``` |
| 17 | + |
| 18 | +```python |
| 19 | +<py-script> |
| 20 | + def say_hello_no_param(): |
| 21 | + print("Hello!") |
| 22 | + |
| 23 | + def say_hello_with_param(name): |
| 24 | + print("Hello " + name + "!") |
| 25 | +</py-script> |
| 26 | +``` |
| 27 | + |
| 28 | +Note that py-\* attributes need a _function call_ |
| 29 | + |
| 30 | +Supported py-\* attributes can be seen in the [PyScript API reference](<[../api-reference.md](https://github.com/pyscript/pyscript/blob/66b57bf812dcc472ed6ffee075ace5ced89bbc7c/pyscriptjs/src/components/pyscript.ts#L119-L260)>). |
| 31 | + |
| 32 | +## Subscribe to event with `addEventListener` |
| 33 | + |
| 34 | +You can also subscribe to an event using the `addEventListener` method of the DOM element. This is useful if you want to pass event object to the event handler. |
| 35 | + |
| 36 | +```html |
| 37 | +<button id="two">add_event_listener passes event</button> |
| 38 | +``` |
| 39 | + |
| 40 | +```python |
| 41 | +<py-script> |
| 42 | + from js import console, document |
| 43 | + from pyodide.ffi.wrappers import add_event_listener |
| 44 | + |
| 45 | + def hello_args(*args): |
| 46 | + console.log(f"Hi! I got some args! {args}") |
| 47 | + |
| 48 | + add_event_listener(document.getElementById("two"), "click", hello_args) |
| 49 | +</py-script> |
| 50 | +``` |
| 51 | + |
| 52 | +or using the `addEventListener` method of the DOM element: |
| 53 | + |
| 54 | +```html |
| 55 | +<button id="three">add_event_listener passes event</button> |
| 56 | +``` |
| 57 | + |
| 58 | +```python |
| 59 | +<py-script> |
| 60 | + from js import console, document |
| 61 | + from pyodide.ffi import create_proxy |
| 62 | + |
| 63 | + def hello_args(*args): |
| 64 | + console.log(f"Hi! I got some args! {args}") |
| 65 | + |
| 66 | + document.getElementById("three").addEventListener("click", create_proxy(hello_args)) |
| 67 | +</py-script> |
| 68 | +``` |
| 69 | + |
| 70 | +or using the PyScript Element class: |
| 71 | + |
| 72 | +```html |
| 73 | +<button id="four">add_event_listener passes event</button> |
| 74 | +``` |
| 75 | + |
| 76 | +```python |
| 77 | +<py-script> |
| 78 | + from js import console |
| 79 | + from pyodide.ffi import create_proxy |
| 80 | + |
| 81 | + def hello_args(*args): |
| 82 | + console.log(f"Hi! I got some args! {args}") |
| 83 | + |
| 84 | + Element("four").element.addEventListener("click", create_proxy(hello_args)) |
| 85 | +</py-script> |
| 86 | +``` |
| 87 | + |
| 88 | +## JavaScript to PyScript and From PyScript to JavaScript |
| 89 | + |
| 90 | +If you're wondering about how to pass objects from JavaScript to PyScript and/or the other way around head over to the [Passing Objects](passing-objects.md) page. |
| 91 | + |
| 92 | + |
| 93 | +### Exporting all Global Python Objects |
| 94 | + |
| 95 | +We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: |
| 96 | + |
| 97 | +```python |
| 98 | +<py-script> |
| 99 | + from js import createObject |
| 100 | + from pyodide.ffi import create_proxy |
| 101 | + createObject(create_proxy(globals()), "pyodideGlobals") |
| 102 | +</py-script> |
| 103 | +``` |
| 104 | + |
| 105 | +This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. |
| 106 | + |
| 107 | +(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a `<script>` tag, since that tag will evaluate before any PyScript has a chance to. We need to delay accessing the Python variable in JavaScript until after the Python code has a chance to run. The following example uses a button with `id="do-math"` to achieve this, but any method would be valid.) |
| 108 | + |
| 109 | +```python |
| 110 | +<py-script> |
| 111 | + # create some Python objects: |
| 112 | + symbols = {'pi': 3.1415926, 'e': 2.7182818} |
| 113 | + |
| 114 | + def rough_exponential(x): |
| 115 | + return symbols['e']**x |
| 116 | + |
| 117 | + class Circle(): |
| 118 | + def __init__(self, radius): |
| 119 | + self.radius = radius |
| 120 | + |
| 121 | + @property |
| 122 | + def area: |
| 123 | + return symbols['pi'] * self.radius**2 |
| 124 | +</py-script> |
| 125 | +``` |
| 126 | + |
| 127 | +```html |
| 128 | +<input type="button" value="Log Python Variables" id="do-mmath" /> |
| 129 | +<script> |
| 130 | + document.getElementById("do-math").addEventListener("click", () => { |
| 131 | + const exp = pyodideGlobals.get("rough_exponential"); |
| 132 | + console.log("e squared is about ${exp(2)}"); |
| 133 | + const c = pyodideGlobals.get("Circle")(4); |
| 134 | + console.log("The area of c is ${c.area}"); |
| 135 | + }); |
| 136 | +</script> |
| 137 | +``` |
| 138 | + |
| 139 | +### Exporting Individual Python Objects |
| 140 | + |
| 141 | +We can also export individual Python objects to the JavaScript global scope if we wish. |
| 142 | + |
| 143 | +(As above, the following example uses a button to delay the execution of the `<script>` until after the PyScript has run.) |
| 144 | + |
| 145 | +```python |
| 146 | +<py-script> |
| 147 | + import js |
| 148 | + from pyodide.ffi import create_proxy |
| 149 | + |
| 150 | + # Create 3 python objects |
| 151 | + language = "Python 3" |
| 152 | + animals = ['dog', 'cat', 'bird'] |
| 153 | + multiply3 = lambda a, b, c: a * b * c |
| 154 | + |
| 155 | + # js object can be named the same as Python objects... |
| 156 | + js.createObject(language, "language") |
| 157 | + |
| 158 | + # ...but don't have to be |
| 159 | + js.createObject(create_proxy(animals), "animals_from_py") |
| 160 | + |
| 161 | + # functions are objects too, in both Python and Javascript |
| 162 | + js.createObject(create_proxy(multiply3), "multiply") |
| 163 | +</py-script> |
| 164 | +``` |
| 165 | + |
| 166 | +```html |
| 167 | +<input type="button" value="Log Python Variables" id="log-python-variables" /> |
| 168 | +<script> |
| 169 | + document |
| 170 | + .getElementById("log-python-variables") |
| 171 | + .addEventListener("click", () => { |
| 172 | + console.log(`Nice job using ${language}`); |
| 173 | + for (const animal of animals_from_py) { |
| 174 | + console.log(`Do you like ${animal}s? `); |
| 175 | + } |
| 176 | + console.log(`2 times 3 times 4 is ${multiply(2, 3, 4)}`); |
| 177 | + }); |
| 178 | +</script> |
| 179 | +``` |
0 commit comments