generic_events_documentation.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from nicegui import context, ui
  2. from ..tools import text_demo
  3. def main_demo() -> None:
  4. """Generic Events
  5. Most UI elements come with predefined events.
  6. For example, a `ui.button` like "A" in the demo has an `on_click` parameter that expects a coroutine or function.
  7. But you can also use the `on` method to register a generic event handler like for "B".
  8. This allows you to register handlers for any event that is supported by JavaScript and Quasar.
  9. For example, you can register a handler for the `mousemove` event like for "C", even though there is no `on_mousemove` parameter for `ui.button`.
  10. Some events, like `mousemove`, are fired very often.
  11. To avoid performance issues, you can use the `throttle` parameter to only call the handler every `throttle` seconds ("D").
  12. The generic event handler can be synchronous or asynchronous and optionally takes `GenericEventArguments` as argument ("E").
  13. You can also specify which attributes of the JavaScript or Quasar event should be passed to the handler ("F").
  14. This can reduce the amount of data that needs to be transferred between the server and the client.
  15. Here you can find more information about the events that are supported:
  16. - https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement#events for HTML elements
  17. - https://quasar.dev/vue-components for Quasar-based elements (see the "Events" tab on the individual component page)
  18. """
  19. with ui.row():
  20. ui.button('A', on_click=lambda: ui.notify('You clicked the button A.'))
  21. ui.button('B').on('click', lambda: ui.notify('You clicked the button B.'))
  22. with ui.row():
  23. ui.button('C').on('mousemove', lambda: ui.notify('You moved on button C.'))
  24. ui.button('D').on('mousemove', lambda: ui.notify('You moved on button D.'), throttle=0.5)
  25. with ui.row():
  26. ui.button('E').on('mousedown', lambda e: ui.notify(e))
  27. ui.button('F').on('mousedown', lambda e: ui.notify(e), ['ctrlKey', 'shiftKey'])
  28. def more() -> None:
  29. @text_demo('Specifying event attributes', '''
  30. **A list of strings** names the attributes of the JavaScript event object:
  31. ```py
  32. ui.button().on('click', handle_click, ['clientX', 'clientY'])
  33. ```
  34. **An empty list** requests _no_ attributes:
  35. ```py
  36. ui.button().on('click', handle_click, [])
  37. ```
  38. **The value `None`** represents _all_ attributes (the default):
  39. ```py
  40. ui.button().on('click', handle_click, None)
  41. ```
  42. **If the event is called with multiple arguments** like QTable's "row-click" `(evt, row, index) => void`,
  43. you can define a list of argument definitions:
  44. ```py
  45. ui.table(...).on('rowClick', handle_click, [[], ['name'], None])
  46. ```
  47. In this example the "row-click" event will omit all arguments of the first `evt` argument,
  48. send only the "name" attribute of the `row` argument and send the full `index`.
  49. If the retrieved list of event arguments has length 1, the argument is automatically unpacked.
  50. So you can write
  51. ```py
  52. ui.button().on('click', lambda e: print(e.args['clientX'], flush=True))
  53. ```
  54. instead of
  55. ```py
  56. ui.button().on('click', lambda e: print(e.args[0]['clientX'], flush=True))
  57. ```
  58. Note that by default all JSON-serializable attributes of all arguments are sent.
  59. This is to simplify registering for new events and discovering their attributes.
  60. If bandwidth is an issue, the arguments should be limited to what is actually needed on the server.
  61. ''')
  62. def event_attributes() -> None:
  63. columns = [
  64. {'name': 'name', 'label': 'Name', 'field': 'name'},
  65. {'name': 'age', 'label': 'Age', 'field': 'age'},
  66. ]
  67. rows = [
  68. {'name': 'Alice', 'age': 42},
  69. {'name': 'Bob', 'age': 23},
  70. ]
  71. ui.table(columns, rows, 'name').on('rowClick', ui.notify, [[], ['name'], None])
  72. @text_demo('Modifiers', '''
  73. You can also include [key modifiers](https://vuejs.org/guide/essentials/event-handling.html#key-modifiers>) (shown in input "A"),
  74. modifier combinations (shown in input "B"),
  75. and [event modifiers](https://vuejs.org/guide/essentials/event-handling.html#mouse-button-modifiers>) (shown in input "C").
  76. ''')
  77. def modifiers() -> None:
  78. with ui.row():
  79. ui.input('A').classes('w-12').on('keydown.space', lambda: ui.notify('You pressed space.'))
  80. ui.input('B').classes('w-12').on('keydown.y.shift', lambda: ui.notify('You pressed Shift+Y'))
  81. ui.input('C').classes('w-12').on('keydown.once', lambda: ui.notify('You started typing.'))
  82. @text_demo('Custom events', '''
  83. It is fairly easy to emit custom events from JavaScript which can be listened to with `element.on(...)`.
  84. This can be useful if you want to call Python code when something happens in JavaScript.
  85. In this example we are listening to the `visibilitychange` event of the browser tab.
  86. ''')
  87. async def custom_events() -> None:
  88. tabwatch = ui.checkbox('Watch browser tab re-entering') \
  89. .on('tabvisible', lambda: ui.notify('Welcome back!') if tabwatch.value else None, args=[])
  90. ui.add_head_html(f'''
  91. <script>
  92. document.addEventListener('visibilitychange', () => {{
  93. if (document.visibilityState === 'visible')
  94. getElement({tabwatch.id}).$emit('tabvisible');
  95. }});
  96. </script>
  97. ''')
  98. # END OF DEMO
  99. await context.get_client().connected()
  100. ui.run_javascript(f'''
  101. document.addEventListener('visibilitychange', () => {{
  102. if (document.visibilityState === 'visible')
  103. getElement({tabwatch.id}).$emit('tabvisible');
  104. }});
  105. ''')