How to handle interdependent events?

In my app I have a Grid with a child component that depends on the clicked row/col in the grid.
This has been handled by my existing itemClicked event handler.

Now I want to also refresh the child component when the user moves around the Grid with the arrow keys. To do that I’ve added a cellFocus event handler.

Now the problem:

When I click with the mouse, I get two events. First the cellFocus and then the itemClick, and I end up doing the child refresh twice.

I could move everything to the cellFocus handler, but I have an extra requirement:
On click I always want to refresh, while on cellFocus I only want to refresh if the focus has moved (ie not when user alt-tabs back to the browser)
So, it looks like I have to have both events.

What is the best strategy to handle interdependent events like this?

  • Let both event handlers check if state is already correct
  • Set a timestamp in first event handler and check that elapsed time < X ms in the next event handler
  • ?

I would definitely avoid relying on any arbitrary time difference.

I saw your previous question. Based on that I would recommend to check if using Selection Grid add-on would be a solution for you: Selection Grid - Vaadin Add-on Directory
It does selection by up/down cursor key movement client side and you do not need to observe it with cell focus listener and do the logic on the server side.
The add-on may be a bit overkill for this single purpose only. The up/down cursor key selection movement could be achieved with simple JavaScript approach too. The solution is demoed here: How do I select Grid rows automatically using up/down arrow keys - Vaadin Cookbook

Totally agree; It is my least favorite option, but in the absence of any good solution you might have to pick the bad one.

Thanks! I’ll check it out

Hmm. Looks like I’m getting more than I want; It removes the selection checkbox column.
I actually prefer to have both the selection column and selecting by (ctrl/shift) clicking the rows themselves.

This one is probably too simplistic for us, but as a proof of concept it was nice

There is an API to re-enable it in the add-on. The default is like that as originally the add-on was developed in Vaadin 7 Table users in mind, as it did not have such column.

You are right. I didn’t expect there to be one, so I didn’t look for it: setMultiSelectionColumnVisible(true)

Looking at the directory page, I see a two year old comment from myself where I also asked about the selection column. Got no answer then, but now I know! Thanks Tatu :smiley:

It should’ve really been documented. Having non-hacky control over the selection column is also something we’ve wanted for Grid

Summary so far using SelectionGrid:

It takes care of:

  • Up/down keyboard navigation; Row gets automatically selected
  • Ctrl/shift click selection in the main list, which mean I can drop my own code for doing this
  • Bonus features:
    • Shift-selection in the selection column
    • Shift-arrow/up/down selection in the main list
    • Being able to choose if I want the selection column or not

It does not take care of:

  • Horizontal keyboard navigation. Still need cellFocus to handle that
  • I also need itemClick for other work. Technically this means I still have the event conflict, but I’ve defined myself around it
  • Moving editor on arrow up/down. Still need keyboard shortcutListener for that

For lists where we select individual cells, I’d also prefer to get the focus ring on click, and not have to wait until I move with the keyboard. Unfortunately, vaadin distinguishes between those two states.
Fixed that by copying the internal styling and removed the :host([navigating]) part of it:

vaadin-grid, vaadin-selection-grid {
    ...
    &.cell-select::part(focused-cell):focus::before {
        content: '';
        position: absolute;
        inset: 0;
        pointer-events: none;
        box-shadow: inset 0 0 0 var(--_focus-ring-width) var(--_focus-ring-color);
    }

}

“cell-select” is a class I add to the SelectionGrids where I want this behaviour.
Seems to work just fine