3 way toggle with intermediate UNDEF position
I needed this toggle switch to show the status of various rooms as all-OFF
, all-ON
or a mixture. I wanted to be able to switch all ON
or all OFF
from the same widget (obviously you can’t select the intermediate position). A standard toggle linked to a grouped item with an aggregation function will show either ON
or OFF
in the mixed state depending on whether the aggregation function is AND
or OR
. If the aggregation is OR
and the status is mixed the toggle will show ON
; clicking the toggle in that state will turn everything OFF
which might not be what you want to do.
The widget below shows OFF
if all are OFF
, ON
if all are ON
and an intermediate state if the group item is UNDEF
i.e. some, but not all, are ON
. Clicking the right side of the toggle will switch all ON
and the left will switch all OFF
irrespective of the current state (NB it is not possible to “slide” the toggle. It’s just a click.
Props are the group item. Members of the group are picked up with a repeater. The group item should be set up as a switch without an aggregation function specified (actually that defaults to EQUALITY
, which gives the required UNDEF
state if not all the members are in the same state).
EDIT
: It now looks right on mobile devices. f7 adds in some secret CSS for mobile devices incuding a min-width
property of 27px for f7-button
s. I needed to override that in the style properties so that the button wasn’t stretched horizontally.
This is my first published widget so I’d be grateful for any sugestions or improvements
uid: GroupToggle
tags: []
props:
parameters:
- context: item
description: Group item without aggregation function
label: Item
name: item
required: true
type: TEXT
parameterGroups: []
timestamp: Feb 7, 2024, 10:29:35 PM
component: f7-row
config: {}
slots:
default:
- component: oh-button
config:
actionItem: =props.item
action: command
actionCommand: OFF
round: true
outline: false
style:
height: 30px
width: 32px
border-radius: 15px 0px 0px 15px
background: =(items[props.item].state === 'ON')?'#f60':'#505050'
position: absolute
left: 0px
- component: oh-button
config:
actionItem: =props.item
action: command
actionCommand: ON
round: true
outline: false
style:
height: 30px
width: 32px
border-radius: 0px 15px 15px 0px
background: =(items[props.item].state === 'ON')?'#f60':'#505050'
position: absolute
left: 32px
- component: f7-button
config:
round: true
outline: false
style:
height: 24px
width: 24px
min-width: 24px
border-radius: 12px
background: =(items[props.item].state === 'OFF')?("white"):(items[props.item].state === 'ON')?("white"):("#707070")
top: 3px
left: =(items[props.item].state === 'OFF')?("3px"):(items[props.item].state === 'ON')?("37px"):("20px")
If you want to test it out, here is a little widget that creates buttons for the group and for its members and shows the 3-way toggle underneath. Clicking the top button - the group item - obviously turns the whole group on or off. Clicking individual buttons can put the group into the mixed state which will be shown on the toggle. Clicking the right or left of the toggle can be used to specify ON
or OFF
from any state.
uid: GroupToggle_Test
tags: []
props:
parameters:
- context: item
description: Group item without aggregation function
label: Item
name: item
required: true
type: TEXT
parameterGroups: []
timestamp: Feb 7, 2024, 10:44:15 PM
component: f7-card
config: {}
slots:
default:
- component: f7-row
config:
style:
height: 30px
slots:
default:
- component: oh-button
config:
action: toggle
actionCommand: ON
actionCommandAlt: OFF
actionItem: =props.item
outline: true
raised: true
round: true
active: "=(items[props.item].state === 'ON') ? true : false"
style:
height: 28px
width: 100px
text: =items[props.item].state
- component: oh-repeater
config:
for: loopItem
groupItem: =[props.item]
sourceType: itemsInGroup
slots:
default:
- component: f7-row
config:
style:
height: 30px
slots:
default:
- component: oh-button
config:
action: toggle
actionCommand: ON
actionCommandAlt: OFF
actionItem: =loop.loopItem.name
active: "=(items[loop.loopItem.name].state === 'ON') ? true : false"
outline: true
round: true
style:
height: 28px
width: 100px
text: =items[loop.loopItem.name].state
- component: f7-row
config:
style:
height: 30px
slots:
default:
- component: widget:GroupToggle
config:
item: =props.item