I have rows of data in a data grid. It is possible for someone to enter nonsense in any row. The proper time to check that is when they leave a row, e.g., click in (or tab to) another row or another component on the form.
Yes, each row could have a “sanity check” button, but that’s easily ignored or skipped, when the user is in a hurry.
Having a sanity-check button on the Grid itself is less intrusive, but easily forgotten, and also much further removed from where the error occurs, in both time and space. (The failing row(s) could have been paged away, no longer visible.)
Ideally, the sanity-checks should occur while the user is right near the place where they made the mistake, and can fix it, and can best learn from it.
What I’ve tried and what’s not working:
I’ve tried digging into the Anvil Docs for a corresponding event, but nothing came up. Likewise for a forum search (“on exit row”).
In this particular case, I think I can probably hack together an alternative. But in the more general case, I’m not so sure.
If I’m understanding it correctly (apologies if I’m not, I’m not a strong word-to-visual person), your data grid looks like this (via double clicking on a row)?
Yes, but that doesn’t guarantee that they’ve completed the row. They may have clicked on (or tabbed to) text_box_2, in the same row. One should check a row-level constraint only when they’re clearly done with that row.
I would write logic in a function that did a sanity check for the row, but it would be triggered by every single entry text box’s lost_focus event in that row. (get parent component etc. etc.)
The CRM/POS (not anvil) where I work does something similar when writing a sales ticket, if you enter ANY information in any field, you can’t proceed until you give it the rest of the information needed to process an order.
It highlights this by raising red error flags, and greying out the ‘Accept Order’ button, but also, when you hover over the little floating red ( ! ) symbol, the tooltips have changed on-the-fly to tell you which field(s) are lacking information.
In your case you could even make something like a CSS red border or something to highlight the unfinished row / empty text boxes. With a tooltip for clarity.
Going further, the row could spin off a timer event that waits a certain amount of time for the row to be completed, then starts raising red notification boxes (that auto-close) informing the user that there were unfinished rows, at some, not-annoying amount of time interval.
Yes, that’s what I’ll end up doing. (Mine aren’t all textboxes, but the same principle holds.)
That works well when each row’s column has its own self-contained sanity check. Which is my current case.
When a sanity check involves multiple columns, however, that can lead to a strange kind of hell, where entering a valid value in column A is impossible until you enter a (related) value in column G, and vice versa. It’s for cases like that, where an on-exit-row event simply and clearly avoids such Catch-22’s. The whole-row check doesn’t happen until you are clearly done with the row as a whole.
Hey @p.colbert After fiddling here’s what I have, yes pretty hacky:
class RowTemplate1(RowTemplate1Template):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
for component in self.get_components():
try:
component.set_event_handler('lost_focus', self.check_row_focus)
except ValueError as err:
pass
try:
# this ones def optional
component.set_event_handler('change', self.check_row_focus)
except ValueError as err:
pass
def check_row_focus(self, **event_args):
if get_focused_component() not in self.get_components():
print("I lost row focus!") # your code here
You could also just manually add a call to self.check_row_focus() in any event you like, so you don’t have to overwrite any of the other events you might have already coded.
Edit: Looking at it again I don’t think setting the change event would do anything. Like if you checked a check box in a different row, it won’t fire the change event on the old row, even if the last thing you checked was a check box. (When you last changed it, of course the focus of the component is on a child of its parent)
I’m starting to think this is why Anvil added add_event_handler and remove_event_handler: so that we could tack on such logic without altering existing handlers. Reference:
I’ve tried something like this before, but I factored out the logic into its own object (class).
Based on your logic, a class instance would be initialized with the components it needed to monitor. This would add event handlers for those events of interest, and use logic to synthesize new “events”, such as the ones I want to use.
The class would need to be flexible enough to accept notice of components added (and removed) since it was initialized. The enclosing form might need to call the instance, to notify it of such changes when it makes them, e.g., when the repeating-panel’s items gets reassigned, or its row-template decides to add/remove components on its own.
This can get messy, pretty quickly. It’s far from a transparent addition. If the underlying framework would have to do equally messy things, to provide this feature, I can see why it might be back-burnered.
For the simpler cases, at least, this organization seems sound, though.