ValueError: Cannot set event handler for unknown event

Hi all,
I’m struggling with Anvil events again.

What I’m trying to do:
I’m trying to implement a set of Form entry custom components (Text entry, Number entry, Email Entry, Form buttons etc). The entry fields can be added to any Form, that should also derive from a FormMixin. To reuse functionality I have implemented form level functionality in a mixin class FormMixin (see discussion here: Form components and inheritance. Possible? - #2 by p.colbert). The mixin handles coordination between the fields.
This works OK (within the limitations of custom components).

Now for my problem: I want the field component to communicate to the Form. For that I have a custom event ‘validating’ that I want my Form mixin (and therefore my Form) to handle without the user having to wire up an event handler.

So the field component does:

self.raise_event('validating')

and I have exposed it in the custom component dialog.

The FormMixin does:

self.set_event_handler('validating', on_validate)

The test form is defined as:

class TestForm3(TestForm3Template, FormMixin):

However when I run the test program I get an error:

ValueError: Cannot set event handler for unknown event 'validating' on TestForm3 component.

So, how do I make the FormMixin aware of unknown events?

Com to think of it, what I really want is the field component events to bubble up to the Form(Mixin), since the field component should not have to know about the Form(Mixin).
How would you handle this situation?

When you define a Custom Component, you get to define Custom Events that it responds to. I’m not aware of anywhere else you can define custom events.

So, perhaps you could define a (non-visual?) component that responds to such events, and place it on the main form?

Another way to think of this is, an Event is a way to decouple sender from receiver. But an Anvil Event is not the only way to do that, and might not be the best fit in some cases. I recall a publish-subscribe library mentioned somewhere on this Forum, that might be a better fit.

here’s the library from @owen.campbell that seems like it might be just what you’re looking for:

If you’re using an event that you haven’t defined as part of the CustomComponent or you want to create a custom event for an arbitrary Component use x-validating instead of validating

linked docs: Anvil Docs | Anvil Components

1 Like

I thought of custom events but am more confused than before. When I define x-validating in the custom component dialog, the dialog changes it to x_validating (note the underscore). OK, I’ll use that then. So I raise x_validating in the Field component. Then I set an event_handler in the Form component for x_validating.
But when I run the app I still get the unknown event error.

@p.colbert @stucork thanks for reminding me of the PubSub library. I knew I had seen it somewhere. I’ll probably have to go that route.

I’m a little confused on how you have things setup, but in general if you want to raise your own events, you put x- in front of the name. I don’t know if that’s a requirement or convention. So you’d register the event handler like this:

self.set_event_handler('x-validating', on_validate)

Then, to call it, you’d have to call raise_event on the same component you registered the event on. Calling raise_event on the field component won’t cause it to call the event handler set on the form.

You can play around with things like self.parent to get to the form itself to raise the event, but that ends up being pretty fragile, based on how you’ve structured your form and how you’ve nested components.

To get the sort of behavior you’re trying to use, you’d need to go with the pub/sub library.

I think at this stage a clone link will be the best way for others to help.

If you’re using a mixin class and correctly registering events then you shouldn’t need the x- prefix.
(this is only if you’re not registering the events in the - “use as component” dialog box)

Here’s an example of it working

https://anvil.works/build#clone:7QYXK2I2XEH4FEY6=4TH6K6GDZDWJC7EK2Y5OYQBE

Also - I may be missing something from your original description but is TestForm3 the container form or the CustomComponent if it’s the container form then it doesn’t have a validating event - it’s only the CustomComponent that does…

@stucork @jshaffstall Your comments and example made me realise that I was hoping for the Form class (with the Mixin) to each to the event of the Field component. Which is doomed to fail.
I now went the PubSub way (using the mentioned library).

PubSub or event bubbling seems like something that Anvil would benefit from having natively. Currently there is no way for components to communicate without having intimate knowledge of each other. Which is usually the point of utilising an event system.

Thanks for all suggestions!

3 Likes

New version of that library coming imminently…

2 Likes

@owen.campbell Cool!
Requests:

  • make logging a global toggle, preferably off by default.
  • can you make it a component library (I mean an Anvil app), like other libraries such as HashRouting. Maybe even add an Anvil demo app.
  • I expected extra kwargs to be passed with the message. Instead I have to use the ‘content’ parameter, which seems a bit cumbersome.

Please note that I have just used the library for one evening, so maybe you shouldn’t listen to me :wink:
Thanks for making the library available.

  • v0.1.4 has some improvements to the logging behaviour.
  • For now, I’d rather publish this via github but there’s nothing to stop you creating your own ‘messaging’ app from this code and using it as a dependency.
  • I’ll have a think about the api for the message itself.
1 Like