Multiple Widget Actions

Since the beginning of MainUI this question has cropped up with some regularity: Can I trigger more than one of the OH widget actions on a component with a single click?

The answer has always, rightly, been: No, you can only define a single action for each component in a widget.

This answer is not 100% true, there are ugly hacks that could allow a click on a link, for example, to trigger the actions of other components, but these are not truly supported nor even advised.

The question (and default answer) came up yet again the other day and I finally found it so unsatisfying that I decided to do something about it. I was looking at the MainUI code trying to decide what the best implementation might be when it occurred to me that there is already a native implementation that should work with just a little css. We just have to change the question to Can I trigger, with a single click, multiple components that each have an action?

The solution takes advantage of the pointer-events css property which allows us to disable an element’s response to mouse clicks and the fact that a click event on a child element will propagate back up the document hierarchy to the ancestor elements. Put simply, if we nest a series of components and ensure that only the lowest element receives the click event all the other components get that event as well.

In practice it looks something like this:

- component: oh-link
  config:
    action: variable
    actionVariable: exampleVariable
    actionVariableValue: NewValue
    style:
      pointer-events: none
  slots:
    default:
      - component: oh-link
        config:
          text: Link for multiple actions
          action: command
          actionCommand: ON
          actionItem: SomeSwitchItem
          style:
            pointer-events: auto

This will appear on the widget as only a single link:
image
because the top link only contains the bottom link and so is sized to the same width and height as the bottom link.

The top link, however, has pointer-events: none so it does not receive any of mouse interactions; instead, those get passed through to the bottom link. The bottom link has pointer-events reset to auto (if you do not specify this, it just inherits none from its parent) so, the bottom link can receive mouse interactions. When it does, its click event is triggered which initiates the command action, but that click event also propagates up the hierarchy and so the parent’s variable action is also initiated. Two actions for one click.

Usage Note:

There aren’t really that many situations where this should be necessary. If you find yourself in a situation with your custom widget where you think you need this solution, you should carefully examine whether or not there is a better way. Nine times out of ten there probably will be. If you’re sending the same command to multiple different items then maybe it’s easier to put them in a group and send a single command to the group. If you’re sending different commands to multiple different items then maybe it’s just easier to trigger a rule. If you’re setting more than one variable then maybe it’s easier to make that variable an object with multiple keys. It’s not even sensible to try and open more than one modal at a time.

In real usage, the most likely place this is required is if you have a situation where you need to set a new value for a widget variable and also some other action simultaneously (combining an action and clearing one or more variable values can already be done).

6 Likes

Great job Justin, as usual :wink:

Would that be one way to use quasi global variables in a widget?

Background: The same calculation appears several times in my Sun2000 widget. I could then simplify this using a global variable.

You are probably looking for something more like the unusal usage of an oh-repeater in this example:

I’ve restarted work on a PR to bring this more formally into OH, but until then you can use that repeater trick to add global constants and callable functions to your repeater code.

Thank you for your answer, but my problem is slightly different. I have a widget with five popups for additional information.

It doesn’t matter that the values are only calculated when they are clicked. I have moved the first oh-link to the top of the listing, and it works like this.