Keydown in form that needs to be re-opened

What I’m trying to do:
Re-open a form with open_form(X) multiple times.

What I’ve tried and what’s not working:
Adding a keydown event listener to self is not listening to key presses, while adding to document is problematic as it gets readded each time you re-open the form.

Code Sample:

from anvil.js.window import document

class Keydown_form(Keydown_formTemplate):
  def __init__(self, **properties):
    self.init_components(**properties)
    if False: # the lines below dont attach the event - flip to True to test
      dom_node = get_dom_node(self)
      dom_node.addEventListener("keydown", self.on_keydown)
    else: #this works but try running open_form(Keydown_form) multiple times, it keeps re-adding the event listener.
      document.addEventListener("keydown", self.on_keydown)

Clone link:
(Anvil | Login)

in the else branch - you’re adding a document level event listener for each form

I would probably use the show/hide events plus a local flag.
(make sure you hook these events up in the designer)

    def __init__(self, **properties):
        self.init_components(**properties)
        self._setup = False
        # edit - added from discussion below
        self.on_keydown = self.on_keydown

    def form_show(self, **event_args):
        if self._setup:
            return
        self._setup = True
        document.addEventListener("keydown", self.on_keydown)

    def form_hide(self, **event_args):
        self._setup = False
        document.removeEventListener("keydown", self.on_keydown)

Unfortunately the show and hide events aren’t perfect opposites of each other
the show event might fire if the form’s visible property gets set to True.
So using the flag is a good way to ensure we don’t do the setup multiple times.

Thank you, but I am still having an issue.
Doesn’t seem like it’s disassigning the listener.

Very subtle

add this to your init method

        self.on_keydown = self.on_keydown

the removeEventListener in JavaScript checks for object identity in order to determine the listener to remove.
But each time we access self.on_keydown we get a new object

    print(self.on_keydown == self.on_keydown) # True - equal
    print(self.on_keydown is self.on_keydown) # False - but not identical
    # we get a new method each time

    # now do:
    self.on_keydown = self.on_keydown
    print(self.on_keydown is self.on_keydown) # True
    # self.on_keydown will now always return the same method

1 Like

Very subtle indeed.

It works like magic now, thank you!

1 Like

fyi - we’ve updated how methods work when passed to javascript
(the call to addEventListener and removeEventListener will now always receive the same identical method)

In other words, your original clone link should now work as expected

1 Like