I need to add 10 keywords to an oh-repeater filter.
As the capabilites for expressions have recently been expanded (e.g. arrow functions) I’d like to ask if I can make use of any of these new possibilities to make the expression smarter.
This sounds a bit wired to me, can you please give an example.
Most I need in my (our) widgets is 5 „filters“.
It is about a widget to show various alarms. I receive the alarms in items containing a key word like overtemp, fire, load_error. But not alle alarm key words should be displayed, just the critical ones. That’s why the filter
component: oh-repeater
config:
filter: loop.rItem.state == "PRIMARY_ALARM"||loop.rItem.state == "OVERTEMP"||loop.rItem.state == "OVERPOWER"||...
for: rItem
fragment: true
groupItem: gAlarms
sourceType: itemsInGroup
Did not try it out, but something like
["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(loop.rItem.state)
might make it a bit shorter …
This results in true but does not return a filtered array. Or maybe I just dont understand how to continue from here.
Cutting this expression into peaces :
filter: loop.rItem.state == "PRIMARY_ALARM"
should give the same result as
filter: (loop.rItem.state).includes("PRIMARY_ALARM")
and the same as
filter: ("PRIMARY_ALARM").includes(loop.rItem.state)
so
filter: ["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(loop.rItem.state)
should work
ok. Then maybe the widget does not support includes. It returned an unfiltered array. Thanks for your answer.
I am just checking in my environment…
Indeed, it is not working like that.
Sorry!
Indeed. Nice code…
I’m on my phone so I can’t easily get the link, but try the object syntax suggested at the bottom of the Creating Personal Widgets
doc page.
Edit:
Here’s the link: Creating Personal Widgets | openHAB
And here’s an example of what I mean. As long the values that you want to filter out are either not keys in the object or are keys that have some falsy value, then the object syntax is about as compact as you’ll get.
uid: filter_demo
props:
parameterGroups: []
parameters: []
tags: []
component: oh-list-card
config:
slots:
default:
- component: oh-repeater
config:
for: test
sourceType: array
in:
- title: A
filter: Apple
- title: B
filter: Banana
- title: C
filter: Cucumber
filter: ({'Apple':1,'Cucumber':1})[loop.test.filter]
fragment: true
slots:
default:
- component: oh-list-item
config:
title: =loop.test.title
one should get same result using
filter: (["Apple", "Cucumber"]).includes(loop.test.filter)
sorry, to be honest I just checked the
loop.rItem.state == "PRIMARY_ALARM"||loop.rItem.state == "OVERTEMP"||loop.rItem.state == "OVERPOWER"||...
part, which (as pointed out by @hmerk too) should produce same result as
["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(loop.rItem.state)
just written in a bit more “compact” way.
Would you mind sharing a sample yaml that gives you problems or more details on what you are trying to achieve since (at least I) don’t full understand the problem. Thx!
I have checked it in my installation and only get an empty result… Something wrong with the array…
for some reason you need to add “()”, i.e. modified example
uid: filter_demo
props:
parameterGroups: []
parameters: []
tags: []
component: oh-list-card
config:
slots:
default:
- component: oh-repeater
config:
for: test
filter: (["Apple", "Cucumber"]).includes(loop.test.filter)
sourceType: array
in:
- title: A
filter: Apple
- title: B
filter: Banana
- title: C
filter: Cucumber
fragment: true
slots:
default:
- component: oh-list-item
config:
title: =loop.test.title
similary in original example above dictionary is wrapped with ()
({'Apple':1,'Cucumber':1})
EDIT: also
filter: '["Apple","Banana"].includes(loop.test.filter)'
and
filter: (["Apple","Banana"].includes(loop.test.filter))
works. Probably related to how yaml parser converts stuff (I guess similar to what is explained here Using Ternary Operators in Widget Expressions)
Sorry, but that’s not what OP wanted.
You are both definfing an array as the source type, but the the source type is a number of several items where he wants to filter only those with a given state.
I have tried it like I described before and it is not working, no differnce if the array of states is surrounded by brackets.
I will do another test with the JSON format later on…
As said above, I probably don’t see the whole picture, but imho
can be simplified via
component: oh-repeater
config:
filter: (["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(loop.rItem.state))
for: rItem
fragment: true
groupItem: gAlarms
sourceType: itemsInGroup
Thanks to all of you for the support.
I can confirm that this expression works:
May I ask again for assistance?
given this filter expression within oh-repeater as above:
filter: (["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(loop.rItem.state))
How would this expression look like outside oh-repeater where I want to get the total number of matches from items within a group? Something like:
text: =(["PRIMARY_ALARM", "OVERTEMP", "OVERPOWER"].includes(items.gAlarmItems.member)).size
I think I need to iterate through members to get their states, but now I am at the end of my capabilities
Not really feasible, alas. The items
object does not give you full access to an item, only the state and display state. The only way to get the information is from an api call such as the repeater makes. There are some workarounds if you nest a repeater inside another repeater. The most straightforward looks like this:
- component: oh-repeater
config:
for: array1
...whatever repeater options you need, including fitlers
map: loop.array1_source <-- Put the whole repeater results array into each element of the loop
slots:
default:
- component: f7-block
config:
visible: =loop.array1_idx == 0 <-- This block is now a block that will be rendered only once but has the full repeater result in loop.array1
slots:
default:
- component: Label
config:
text: =loop.array1.length <-- Any component in the block can now access the array1 methods and properties
- component: oh-repeater
config:
for: array2
sourceType: array
in: =loop.array1 <-- The repeater doesn't need to make another API call, it can just use the result array from the first repeater
slots:
defaults:
...use loop.array2 to do whatever you want with your repeated elements
Thanks Justin,
a little bit beyond my capabilities this workaround but try to recap your solution.
Thanks a lot!