Skip to content

Events such as keydown and keyup are not triggered by an ui.input when not assigned directly upon creation #4154

Open
@Alyxion

Description

Description

During the development of a Typeahead component which attaches itself visually to the bottom of an ui.input field to (later) show search result data from a DB, i stumbled over a potential bug when modifying certain event_listeners such as keydown and keyup via the element.on method "post creation".

image

Situation:

  • An ui.input field is created
  • A focus handler is set up via .on("focus", handle_focus) and a blur_handler is setup via on("blur", handle_blur)
  • In handle_focus the.on("keydown", handle_keydown) is assigned to track cursor key presses
  • In handle_blur the event listener is removed again.
    • As NiceGUI doesn't officially support removal of event listeners added via .on yet there is a helper class involved which "cleans up again" / can unassign event listeners, but that just as side note and has no impact on this report / test as you can see in the example code attached below.
  • Expected behavior: handle_keydown will be called when a key is pressed.
  • Actual behavior: It is not

If a "keypress" or "keyup" listener is assigned later and not directly upon creation of the input field, so e.g. delayed by a timer or an event, then the handlers will never be called. If they are assigned directly upon creation, so before everything goes through the websocket from Python to JS, then they work though.

If I assign the same events directly via JavaScript to the DOM element w/ help of the new getHtmlElement function though then everything works perfectly fine. Thus there seems to be some synchronization kind of issue for certain events. A delayed assigned blur event just for example works like a charm.

from nicegui import ui

@ui.page('/')
async def index():
    log_area = ui.scroll_area().style('height: 200px; width: 400px')

    def log_key(e):
        with log_area:
            ui.label(f"Key pressed: {e.args['key']}").classes('font-mono text-xs').style('line-height: 1; margin: 0; padding: 0;')
        log_area.scroll_to(percent=1.0)

    with ui.row():
        input1 = ui.input()
        ui.run_javascript(f'''
            getHtmlElement({input1.id}).addEventListener("keydown", () => console.log("keydown on input1 via js"));
            ''')
        input1.on('keydown', log_key)   # will be triggered
        input1.on('keydown', js_handler='() => console.log("keydown on input1")')  # will be triggered
        input2 = ui.input()

    def attach_event():
        input2.on('keydown', log_key)  # will NOT be triggered
        input2.on('keydown', js_handler='() => console.log("keydown on input2")')  # will NOT be triggered
        input2.on('blur', lambda e: print('blur'))  # will be triggered
        ui.run_javascript(f'''
            getHtmlElement({input2.id}).addEventListener("keydown", () => console.log("keydown on input2 via js"));
            ''')  # will be triggered    

    # setup timer which attaches the event
    ui.timer(1.0, attach_event, once=True, immediate=False)
    
ui.run()

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions