Richie1972
(Richard Rogers)
October 5, 2022, 8:20am
1
Hi,
I’m starting to look at some redesign work on my frontend and I’m struggling a little on understanding which javascript functionality can be used in UI widgets.
For example; in a repeater I see you can do something like:
loop.item.tags.includes("TagName")
However, something a little more complex like trying to check if any elements of an array exist as a tag fails:
props.showSensors.split(",").some(element => loop.item.tags.includes(element))
Error I get is something like:
Expected comma at character 42
So, I’m guessing you can’t have javascript expressions like this in widgets.
It’s difficult to know what you can and can’t do in widgets, so I was wondering if there’s any sort of rough guide.
Thanks,
Richie
rlkoshak
(Rich Koshak)
October 5, 2022, 1:47pm
2
See Building Pages - Components & Widgets | openHAB
The repeater widget has a few more options to build and iterate over the list. oh-repeater - Repeater | openHAB
Nowhere is any arbitrary JavaScript allowed though. Only these subsets.
1 Like
JustinG
(JustinG)
October 5, 2022, 3:00pm
3
The widgets use the expression-eval library which you can find here .
That’s based on jsep, and there you can find a very brief help doc .
The issue with your code is the arrow function. That’s not permitted in the expression-eval library. Alas, no function declarations of any kind are permitted, as far as I can tell, which makes many of the Array
methods (which are permitted) useless.
I’ve been meaning to start up a github issue to discuss this, there are some options that would improve what’s allowed in the expressions.
4 Likes
JustinG
(JustinG)
October 5, 2022, 3:17pm
4
Here’s a github feature request:
opened 03:15PM - 05 Oct 22 UTC
enhancement
main ui
As the community gets more involved in advanced custom widget creation, more and… more users are running up against the limitations of the expression-eval library. In particular, I've seen many issues with users wanting regex expressions or js methods that require functions as parameters. Expression-eval does not handle either of these two cases.
There's a recent fork of expression-eval, [jse-eval](https://github.com/6utt3rfly/jse-eval/), which adopts the jsep plug-in system which, in turn would allow the addition of regex and arrow plug-ins. Is it feasible/acceptable to move MainUI from expression-eval to jse-eval?
1 Like
ysc
(Yannick Schaus)
October 6, 2022, 6:45pm
5
You can have a look at the unit tests of the expression-eval library to figure out roughly what’s possible:
require('source-map-support').install();
const expr = require('./dist/expression-eval.js');
const tape = require('tape');
const fixtures = [
// array expression
{expr: '([1,2,3])[0]', expected: 1 },
{expr: '(["one","two","three"])[1]', expected: 'two' },
{expr: '([true,false,true])[2]', expected: true },
{expr: '([1,true,"three"]).length', expected: 3 },
{expr: 'isArray([1,2,3])', expected: true },
{expr: 'list[3]', expected: 4 },
{expr: 'numMap[1 + two]', expected: 'three'},
// binary expression
{expr: '1+2', expected: 3},
{expr: '2-1', expected: 1},
{expr: '2*2', expected: 4},
This file has been truncated. show original
(ignore the last two, ‘this’ and custom operators)
The identifiers used in the tests refer to the ‘context’ defined here:
const context = {
string: 'string',
number: 123,
bool: true,
one: 1,
two: 2,
three: 3,
foo: {bar: 'baz', baz: 'wow', func: function(x) { return this[x]; }},
numMap: {10: 'ten', 3: 'three'},
list: [1,2,3,4,5],
func: function(x) { return x + 1; },
isArray: Array.isArray,
throw: () => { throw new Error('Should not be called.'); }
};
The actual context you have at your disposal is documented in https://www.openhab.org/docs/ui/building-pages.html#dynamically-configuring-components-with-expressions
1 Like
ysc
(Yannick Schaus)
October 6, 2022, 6:59pm
6
Now that I think of it, defining a custom operator like
@'ItemName'
which would be equivalent to:
items['ItemName'].displayState || items['ItemName'].state
(which has been reported as a pain point several times)
might prove very useful?
3 Likes
JustinG
(JustinG)
October 6, 2022, 10:57pm
7
ysc:
Now that I think of it, defining a custom operator like
@'ItemName'
which would be equivalent to:
items['ItemName'].displayState || items['ItemName'].state
This is inspired! If you don’t mind, I’ll take a shot at this too while I’m looking into the other parser improvements.
3 Likes
JustinG
(JustinG)
October 13, 2022, 6:52pm
8
Richie1972:
However, something a little more complex like trying to check if any elements of an array exist as a tag fails:
props.showSensors.split(",").some(element => loop.item.tags.includes(element))
Error I get is something like:
Expected comma at character 42
So, I’m guessing you can’t have javascript expressions like this in widgets.
It’s difficult to know what you can and can’t do in widgets, so I was wondering if there’s any sort of rough guide.
Thanks,
Richie
FYI: Arrow functions (along with the new @
operator) now work in the latest snapshot version. Although be advised, if you upgrade to a snapshot at the moment there still seems to be a small issue with authentication .
2 Likes