Gotcha with calling Python from Javascript

I just ran across this gotcha recently. When in Javascript code you can use anvil.call to call back to Python code. The first parameter to anvil.call is a DOM node. That can be a DOM node on a form, and it’ll work its way back up to the form to make the Python call there.

The problem comes when one of the components is a Custom HTML component. It’s recognized as the enclosing form and the Python function is called on it instead of on the actual enclosing form.

I ran into this when I switched one of my custom components from blank panel to custom HTML, and all of a sudden the Javascript calls were targeting it instead of the enclosing form.

I don’t know if this is expected behavior or not, but I certainly didn’t expect it, so figured this might help someone else.

Here’s a clone that shows the behavior: Anvil | Login

The clone has a blank panel container and a custom HTML container, both of which contain an embedded component that calls the same Javascript function.

This sort of thing is why we would recommend against using anvil.call() these days. The modern Javascript interop (anvil.js and friends) means you can make Python functions available to Javascript directly.

Even if you want to be able to do a global call from JS to Python, you can do something like:

from anvil.js import window

def my_function(args):
  ...

window.my_function = my_function

…and then from JS, you now have a global my_function() you can call from anywhere!

5 Likes

Yeah, this was from a project that isn’t using the modern Javascript interop. All the Javascript code in it could be ported over to Python and the problem would go away.

I do like the injection of a Python function into the Javascript scope, though, that’s slick.