[wiki] Building Pages in the OH3 UI: documentation draft (2/3)


As this new concept of pages is getting fairly complex but the feature set is stabilizing, I thought it might be about time to start drafting the documention for it so that a good enough iteration could make its way to the docs before the OH3 release. I also planned to talk about them briefly in the [wiki] Getting Started with OH3: rewriting the tutorial - 1. Introduction tutorial rewrite, but this is more of a deep-dive. As always this is going to be a wiki so if you feel like correcting spelling mistakes or the language, or rewrite some parts, feel free to click on that edit button!


TOC:

I. Pages basics

  1. Concepts: UI components, pages & widgets
  2. Relation to sitemaps
  3. Types of pages
  4. Page editors, creating a page & adding widgets

II. Editing pages & widgets: general information (this topic)

  1. Configuring widgets
  2. The system & standard libraries, default widgets (standalone, list items & cells), adding widgets from the model
  3. Widget actions
  4. Expressions
  5. Personal widgets: development & usage

III. Building specific types of pages

  1. Layout pages
  2. Floor plans & maps
  3. Chart pages
  4. Tabbed pages

Link to part I

5. Configuring widgets

No matter which type of page you’re editing, the designer will feature black buttons beside most widgets, that open a contextual menu for the widget in question:

These menus will in most cases allow you to:

  • configure the documented parameters with a config sheet (“Configure Widget” or similar);
  • open the part of the page’s YAML representation pertaining to the widget (“Edit YAML”), that is, a subgraph of the page’s component tree with that widget as its root component;
  • perform cut/copy/paste operations, if supported (you can only do that in the same page currently, to copy or move widgets between pages, you may use the YAML view);
  • reorder the widget within its parent slot (these options are usually named “Move Up” and “Move Down” although you may occasionally encounter other labels, like “Move Left”/“Move Right”);
  • remove the widget.

Configuring the widget with the config sheet is of course more user-friendly than editing the YAML, as the options are usually organized logically in groups and feature a description:

However, it’s important to know that there are limitations and sometimes editing the YAML directly will be best, because:

  1. not all options are described, since widgets are often wrappers for a similar concept in the library it’s based on, either Framework7, ECharts, Leaflet, or other specialized libraries. This means that as a rule, these underlying concepts will usually be passed the key/values of the (openHAB) widget component’s config so that more parameters can be accepted than those which are documented in the widget’s definition. Sometimes it will be indicated somewhere when configuring the widget, or in the openHAB documentation itself, on the other hand some options won’t be available fo use (for instance, because they expect a callback function and you cannot define those in the widget’s config) or need some transformation.
  2. Sometimes you’ll want to use an expression to configure the property, but the UI will get in your way - for instance, it will display an item picker while your intention is to set the prop value to be =props.item1. See below to learn more about expressions.
  3. To quickly and efficiently duplicate similar widgets with only a few differences, it is always way easier to copy/paste the relevant YAML in the editor.
  4. Share the widgets with others in the forum.

Besides, there are several options that virtually all widgets in layout pages, map pages and plan pages accept, all of which are not currently available in the config sheet:

  • visible: you can specify a false boolean to this option to hide the widget. This powerful feature, combined with expressions (see below), allows you to dynamically show widgets or even entire sections (if you use it on layout widgets containing other widgets), depending on the state of your items;
    Example: visible: =items.TV_Powered.state === 'ON' && items.TV_Input.state === 'HDMI1'
  • visibleTo: this accepts an array of strings like role:administrator, role:user, or user:<userid>, allowing the widget to be only visible to specific users or those with a certain role (as mentioned previously in part I, this is not a security feature).
    Example: visibleTo: ["user:scott", "role:administrator"]
  • class and styleare standard Vue.js attributes and can be used to either alter the CSS classes or add inline styling to the component.

6. The system & standard libraries, default widgets (standalone, list items & cells), adding widgets from the model

To help you define useable pages, there are a number of built-in widgets that you can use - most of which will be in layout pages. Those built-in widgets revolve around several libraries:

  • the System library includes “crude” controls that you cannot add with the designers - for instance oh-button, oh-slider, oh-colorpicker. Instead, you’re more likely use them within some container (card, list item…) provided by a widget of the Standard library; but when designing a personal widget with a complex layout you may want to use one or several of them directly. You may also use them in a slot of another widget, for those which define some, in order to add additional controls to that widget.
  • the Standard library, which has several classes of widgets:
    • layout widgets, examples: oh-block, oh-masonry, oh-row, oh-col that you usually add with the designer to a layout page;
    • standalone widgets, examples: oh-label-card, oh-slider-card, oh-player-card - usually not much more than widgets from the System library wrapped in a card;
    • list item widgets, examples: oh-list-item, oh-stepper-item, oh-toggle-item - widgets that are thinner than the standalone ones, which you can only add a part of a list (oh-list or oh-list-card);
    • cell widgets, examples: oh-cell, oh-knob-cell, oh-colorpicker-cell: these widgets are fixed-size cells that you can only add to a oh-cells container widget immediately below a oh-block in a layout page - they will either perform an action - switching a light on & off - or expanding to reveal additional controls;
    • page-specific widgets, for instance map pages have oh-map-marker or oh-map-circle-marker, charts have different types of widgets than the rest to represent axes, series etc.

Of all these classes, these three are the most important: standalone, list items and cells; that’s because they can be used to provide representations of items.
You may have noticed in various parts of the administration pages of the UI that you can operate your items without ever having configured a widget for them: indeed it will try to figure out a “default representation” of this item (either a standalone version, or a list item version, or a cell version), using the item’s type, semantic class & property, state & command description and other means.

You may want to alter this representation though, if the auto-generated one is not optimal or plain wrong; for that, you can use the 3 metadata namespaces widget, listWidget, cellWidget to configure the default representation as you would configure the widget on a page. You can do it for instance from the Model page or the item’s details page:

Then you can either choose another widget type of the same class from the Standard library if you prefer, or use a personal widget (see below). As a general rule, widgets controlling an item feature an item property; when configuring the default representation, you shouldn’t configure this property because it will be automatically be replaced with the name of the item being represented. However, you’ll still have to specify other item properties needed by the widget beside the “main” item (for instance for a oh-player-card widget, the album/track items if relevant).

Having this concept of a default representation also helps you add several items at once on a layout page: when asked to choose which widget you want to add, select “Add from Model…”:

You will then be presented with a tree view of your semantic model of items, and be able to choose several of them at once to add to the parent container - depending on the nature of that container, it will add default standalone representations, or list items, or cells. You can then modify them individually locally for the page.

Important: the widgets added to pages from the model will instantiate the default representation at the time of the addition, either the auto-generated one or the overridden one in metadata, but it will not reflect further changes you make to the default representation by modifying the metadata again.

7. Widget actions

When configuring a widget, you will encounter options related to actions (usually, when something is clicked or touched, but there might be several actions configured for a single widget, for instance, clicking on different parts or a long tap with a touch device); regardless, they will all have the same options:

These action options allow you to configure the interactivity within your pages, as well as the relation between them, in an extensive way. You can navigate to another page, display additional controls, popups and other modals, send commands to items every time a widget allows you to choose an action. For instance, a floor plan marker might either open another page in a popup, or toggle an item.
Configuring the action type reveal more options in the action sheet:

image

The name of options related to a certain action are all prefixed with the same string (usually action for the default action) to distinguish them from the other options of the widget, or those related to another action.

8. Expressions

Virtually everywhere - with the notable exception of chart pages - every time you need a config prop to be dynamically updated, you can use an expression to configure it. Expressions are string literals beginning with the symbol = and everything after it is evaluated using a syntax very similar to JavaScript, you can use arithmetic or string operations etc., the conditional (ternary) operator, as well as the following objects (subject to evolutions):

  • items is a dynamic key/value dictionary allowing you to retrieve the state of items; the result of items.Item1 will be an object like { state: '23', displayState: '23 °C' } (displayState may be omitted). You can therefore use items.Item1.state to use the current state of Item1 in your expression, if it changes, it will be reevaluated;
  • props is a dictionary of the key/values of self-defined props for the current personal widget, or page (pages, like any root UI components, may indeed have props). It is indispensable to use props in expressions when developing a personal widget;
  • the JavaScript Math object (so your can use _Math.floor(…), Math.round(…) and the like;
  • the JavaScript JSON object to parse or produce JSON;
  • theme which holds the current theme: ios, md or aurora;
  • themeOptions and device allow to use the relevant objects that you can see in the About page, Technical information, View details, under clientInfo

Examples of expressions:

=(items.Color1.state.split(',')[2] !== '0') ? 'On ' + '(' + items.Color1.state.split(',')[2] + '%)' : 'Off'

Translates the third part of the HSB state (brightness) of the Color1 item to On or Off.

icon: =(items[props.item].state === 'ON') ? 'f7:lightbulb_fill' : 'f7:lightbulb'

Use a filled icon of a lightbulb but only if the state of the items passed in the prop item is ON.

9. Personal widgets: development & usage

You can extend the library of widgets you have at your disposal by creating personal ones, either by yourself, or copy-pasting from examples by the community; then you can reuse them on pages, multiple times if need be, simply configuring their props to your needs.
To add a new personal widget, as an admin, click on Developer Tools then Widgets. Use the ‘+’ button to create a new one:

The splitted view features a code (YAML) editor and a live preview, you can change the orientation with the button in the center of the bottom toolbar.
Don’t forget to change the uid right away because you won’t be able to alter it afterwards.
Sometimes the live preview will fail to update, you may want to hit the Redraw button or Ctrl-R/Cmd-R regularly when designing your widget.

To actually see how the config sheet would look like, and specify props for your widget for the live preview, click on Set props (Ctrl-P) and configure them as needed:

After saving the widget, you will have it as an option (under “Personal widgets”) to add it to a layout page, or display in a modal like a popover, or use it as the default representation of an item.

Note the special widget:<uid> syntax for the component type to specify “use this personal widget here”, the config being the passed as props to the widget:

component: widget:widget_0a26c10a4d
config:
  prop1: Test
  item: Color1

To efficiently build widgets, you will have to rely often on the style and class properties, in conjunction with Framework7 typography classes, CSS variables, and Vue components, notably the layout grid, and others.

Example of a personal widget:

(exercice for the reader: replace the hardcoded values with expressions sourcing data from items using the prefix prop and string concatenation)

image

uid: weatherforecast
tags: []
props:
  parameters:
    - description: Prefix for the items with the data
      label: Item prefix
      name: prefix
      required: false
      type: TEXT
  parameterGroups: []
component: f7-card
config:
  title: Weather Forecast
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            config:
              class:
                - display-flex
                - justify-content-flex-end
                - align-content-stretch
                - align-items-center
            slots:
              default:
                - component: Label
                  config:
                    text: Heavy Rain
                    style:
                      fontSize: 24px
          - component: f7-row
            config:
              class:
                - display-flex
                - justify-content-space-between
                - align-content-stretch
                - align-items-center
            slots:
              default:
                - component: f7-icon
                  config:
                    f7: cloud_rain
                    color: blue
                    size: 50
                    class:
                      - margin-horizontal
                      - float-left
                - component: Label
                  config:
                    text: 7°C
                    style:
                      fontSize: 36px
                      fontWeight: 600
          - component: f7-row
            config:
              class:
                - display-flex
                - justify-content-space-between
                - align-content-stretch
                - align-items-center
            slots:
              default:
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud
                          color: blue
                          size: 24
                          class:
                            - margin-top
                      - component: Label
                        config:
                          text: 6°C
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud_drizzle
                          color: blue
                          size: 24
                          class:
                            - margin-top
                      - component: Label
                        config:
                          text: 7°C
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud_sun
                          color: blue
                          size: 24
                          class:
                            - margin-top
                      - component: Label
                        config:
                          text: 5°C
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: sun_max
                          color: blue
                          size: 24
                          class:
                            - margin-top
                      - component: Label
                        config:
                          text: 8°C
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud_heavyrain
                          color: blue
                          size: 24
                          class:
                            - margin-top
                      - component: Label
                        config:
                          text: 7°C
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: Paris, France
5 Likes
  • Do the buttons appear as white if using dark mode? I am correct that I saw you’ve implemented a dark mode? I see stuff whizz by on github and sometimes come to the wrong conclusions.

  • Provide links to Framework7, ECharts, and Leaflet docs perhaps?

Love the example at the end!

I’ve not been able to get much beyond spinning up OH 3 in a docker so far. I hope to soon start to really experimenting with it in the coming weeks and I hope to have more substantive contributions to these tutorials at that point. I don’t think zwave and zigbee are available on OH 3 yet so I can’t move my production server over yet.

Yes there’s a dark mode and I hope those who use it (@wborn notably, as do I) would vouch for it :wink:

Yes that’s a big issue, you never know what is available unless you almost reverse-engineer the entire thing; so for certain types of widgets I have contemplated adding a “reference URL” indication to the widgets descriptions, in order to have a handy link to the relevant reference documentation in-app. When you configure it in code view you’ll get a link to the reference document from the original library, so you know what’s potentially available. Of course it would be better to have every compatible option properly documented in the OH docs, or the widget definitions, but we’re talking about hundreds of options, we don’t have the bandwidth to describe them all and it wouldn’t even be reasonable; it’s also a moving target anyways since the libraries evolve and we can’t follow them all.

2 Likes

Thank you very much for your efforts on creating this documentation! It took me some hours to dig into the ‘new’ UI concept, but slowly I begin to understand.

As you pointed out, there are some custom ‘oh-’ components besides the native ones from the f7 framework. These oh- components seems to work with custom parameters (as for example ‘action’ or ‘actionPage’)

Is there any documentation on enabling similar mechanics for custom widgets (for example: Implementing the action- or actionPage selection list in the widget-configuration)

This would also be a perfect addition for the already existing infos in this doc.

1 Like

Thanks for giving it a try; that’s a good question and use case and unfortunately an interesting limitation as well.

As you probably understood your can define props for your widget and pass them as config to components comprising it, using an expression (like =props.prop1). The parameters related to actions are somewhat special because they’re dynamic based on the type of action you select. They are defined in the code here and it’s not currently possible to have these parameters described in a custom widget, but it would be interesting to have a way to do it, I’ll try to find a solution. It will probably involve setting a context to a parameter group, i.e.:

props:
  parameterGroups:
    name: action
    label: Action
    context: action

Then the group with the action context would define the dynamic parameters necessary for configuring the action (they will be prefixed with the name of the group).

However if you’re only interested in the “navigate to another page” action and need a parameter to choose the page in question, then all you have to do is define a parameter in props with type: TEXT and context: page.

props:
  parameters:
    - name: targetPage
      label: Page to navigate to
      type: TEXT
      context: page
...
  component: oh-button # Or another component accepting action parameters
  config:
    action: navigate # hardcoded
    actionPage: =props.targetPage

But I agree this should be better documented - page is a context specific to the UI so it’s not mentioned in the ConfigDescriptionParameter Javadoc.

1 Like

I think this would be a neat addition for widget creators - the context sounds like a good idea and the extra lines of context-code should not bother too much.

I bridged the page-links by adding f7-links or using nested oh-list-elements until now (with some annoying drawbacks) - so yes, the page-context definitely helps. :slight_smile:

There are 3 more questions which maybe fits here - if not, tell me and I will move them.

  • Is there a reason that almost all f7-components are somewhat rebuild as a ‘custom’ oh-widget besides timeline, datetime pickers and a few others? Or is it just work-in-progress?

  • I ask this, because I saw a question in this forum today, where someone was asking for some kind of “execution-timer” in OH3, so I gave myself a homework, trying to build one.
    While doing so, I stucked at the point where I implemented the ‘f7-input’ for the time-selection and want it to talk with the oh-button that should send the execution-time to selected openhab-item.

    • Can you work with variables inside the YAML structure to exchange values between different components? Or is this a limitation due to the missing oh- version of this component?
  • Is there a way to set parameters for the whole page component, for things like page-background etc.

That’s because the f7 components alone aren’t “wired” to anything and in some cases some openHAB-specific logic is necessary to make them useful. For example, the f7-toggle alone won’t do anything, that’s why there’s a oh-toggle which allows it to control an item and reflect its state.

No, the components cannot share information between themselves, so this kind of advanced interactivity is not currently supported. If there’s a need for an “oh-input” in the system library I’m sure it will be added eventually.
The idea behind the custom widgets was more to allow building custom layouts around the existing widgets in the system library - sliders, labels, toggles, buttons; for example, a complete thermostat control with a knob to change the setpoint, some buttons and a temperature/humidity reading - than to provide missing logic or interaction flows. But it’s pretty new and largely untested in the field so the feature set might be extended in the future.

Setting a page background would have to be implemented in the page component itself, it probably won’t work out of the box - the oh-layout-page is not actually based on f7-page, the actual f7-page is higher in the DOM hierarchy.

However, while it’s not done yet, it’s very much on the todo list to add the ability to define props for pages similarly to custom widgets; in other words, parameterized pages. If you have, say, multiple
identical thermostats or other devices and you designed a full page to control one, you wouldn’t have to duplicate that page for every device. You’d design the page once and for all and define props to configure the items, then you could set those props where that page is referenced (for instance in a tab of a tabbed page, or for certains types of actions: navigate, popup, sheet, etc.).
I hope I’ll explain this better when I get around to writing the 3rd article in this series.

This makes sense and reflects my results in creating some custom widgets out of f7-components where there is no oh-equivalent - partly possible but a bit tricky to nest oh-components (with already existing logic and styling behind it) inside of f7-components.

These 2 requirements feels somewhat related to each other, arent they?
If there is an input-component, there have to be some way to define an action trigger (like e.g. a button) to send the value to the item?! A similar approch as in the gauge or slider widget (display the current state and setting the new state in the same element) wouldn´t work here or at least wouldn´t be as dynamic when it comes to widget creation, or am I wrong?

I would definitely vote for this feature, as I feel its missing a long time now. Where would be the right place to make my interest on this visible, find other people with the same need and bringing this topic to the backlog? Is a guithub issue suitable for this or should I open a thread in this forum?

I´m with you, that widgets shouldn´t have more logic than the system behind it - but I definitely see the need for a deeply customizable UI which IMHO is key for a good UX.
Especially when it comes to motivate new people entering the world of homeautomation and let OH stands out with it´s flexibility and beauty (this is a thing, every homeautomation system struggles with the most as it feels).

The current set of custom components are already nice to build up some fancy looking widgets, although some of them are a bit complex in its base structure, what makes it hard to build things around them (e.g. oh-list-card).

If this base component-set will grow and things like the input-components will be implemented, I see an even greater future for OH and a lot of fun for widget creators.
While fiddling around with everything, I was able to ‘clone’ nearly every image (of the first page :smiley:) for the google search term “smarthome ui concept” (although obviously not all of them interacting with OH items right now) - LOVING IT!

Glad to hear :slight_smile:

This will be very helpfull!

Thanks again for all your efforts for this community and your quick and detailed answers.

1 Like

If you have specific pain points please feel free to open issues in https://github.com/openhab/openhab-webui/issues (preferably, rather than here).

Thinking about that a bit more, having an ability to set variables and then access them in expressions looks doable, and might just work for this use case. Something like:

- component:oh-input
  config:
    type: datetime
    variable: alarmTime # sets widget-local variable "alarmTime" on change
- component: oh-button
  config:
    action: command
    actionItem: AlarmTime
    actionCommand: =vars.alarmTime # "vars" contains a key-value map of variables

The existing widgets like sliders, steppers and knob could also be extended to set a variable instead of sending commands to an item directly - so you could confirm the new state with a separate button and probably other things too :thinking:

Really? That’s awesome! If you can share some of that I (and certainly others) would be very interested!

1 Like

(By the way: there’s a marketplace proposal being discussed/in the works to distribute out-of-distro add-ons, rule templates and more, I’m advocating for it to be community-moderated like the HABPanel widget gallery and custom widgets would also hopefully be able to be distributed that way.)

Perfect! I´ll do that.
For a non-technical person its sometimes hard to find the right place for your concern. :slight_smile:

If this would be an optional addition to each widget component, this would be a blast, I think :+1: - you can count on me as a beta tester!

I´ll do so! Have to do some beauty work on the YAMLs and making screenshots later this day, so I can post them here tonight, I think.


Sorry, but didnt find any time atm due to sick kid and wife - and my personal demand prohibits me to just clash in some pictures here, without offering any source implementing and develop the seen things for yourself.

So I just cobbled together at least one widget, that is (with a little effort) reussable for different cases.

It looks like this and supports the most oh-list-components for the bottom row (slider, button, stepper, toggle and more or less icons). It´s working mostly correct on all devices I tested it with (web, ios, android)
2020-09-22 00-02-09
brightness_variants

Further more I already roughly cleaned up the color-changing widget of this ‘theme’, which looks something like:
color_example

All of the color and icon ideas came from a dribble UI concept I found via google from Amogh Srivastava (thx! https://dribbble.com/shots/11450842-Smart-Home-UI-Concept#shot-description)

You can find the first itteration of the brightness example from above on a github repo - rebuild it, extend it, use it, do whatever you like: https://github.com/rgrollfitz/oh3-widgets

Disclaimer: I only have basic experience in working with css and none with the infinite nested yaml-structure. So please keep this in mind while watching the repo. :slight_smile:

Having some more conecept ideas lying around here and will finish and post them in this forum, as soon as I find time.

At last, I want to attach some notes (mostly questions :stuck_out_tongue:) I took during the process of creating these widgets:

  • Would be nice to have a way to react on the different breakpoints via YAML (similar to media queries)
  • oh-link and oh-image doesn´t support setting actions (it seems, that just oh-button & oh-list-item offers this functionality?!)
  • No access to the different css sub classes like :hover (annoying e.g. in case of misusing oh-button as a clickable overlay)
  • No standalone oh-icon class available - would be nice to have one
  • Not possible to use math functions or exeptions in actionCommands
  • The oh-slider item reports an error in the widget-config, if you select a 0 as min-value (it works flawelessly if you set it via yaml)
  • Nice to have: Interacting with svg parameters like we could do in habpanel, to make things move, spin or glow.
  • Expressions doesnt work in styles
  • Boolean toogle in settings isnt working for things like ‘visible:true/false’ (tested on oh-stepper-item) - maybe there are some extra “”, which shouldnt be there?
    • Workaround: ‘class: =props.yourProp ? props.yourProp : “display-none”’
  • Is it possible to use transformation in rules?
  • How to change the site-content depending on a selection made in an element like e.g. a header-slider for selecting the rooms?
4 Likes

That looks awesome @RGroll! I’m glad you’re giving this concept a spin so thoroughly and apparently are having some success with it, it’s encouraging. Many thanks for sharing your work as well.

Your feedback mostly makes sense, I can’t address every point you raised individually now but will later (“expressions don’t work in styles” is particularly true), I think the majority of them can be somewhat resolved one way or another.

1 Like

Can someone smarter than me post an example of a collapsible list? I’ve spent too much time on this already. It seems like the following should work:

component: oh-list-card
config:
  accordionList: true
  title: All Services Status
  footer: Online status of home automation related services
slots:
  default:
    - component: oh-label-item
      config:
        item: ServiceStatuses
        title: All Services
        subtitle: When OFF one or more services are offline
        icon: oh:network
      slots:
        accordion:
          - component: oh-label-item
            config:
              item: vArgus_Status
              title: argus
              subtitle: Home automation server
              icon: oh:network
            slots:
              accordion:
                - component: oh-label-item
                  config:
                    item: vInfluxDB_Status
                    title: InfluxDB
                    subtitle: Home auotmation database server
                    icon: oh:network
          - component: oh-label-item
            config:
              item: vCerberos_Status
              title: cerberos
              subtitle: Garage sensors and actuators
              icon: oh:network
          - component: oh-label-item
            config:
              item: vFafnir_Status
              title: fafnir
              subtitle: NAS server
              icon: oh:network

Thanks!
But when I try the above all I see is

I’m clearly doing something wrong for the subsequent list Items after “argus” but I can’t see what that would be.

I an just guessing. Is there a slot and accordion to much after argus??

My intent was to have argus also be an accordion that opens up. So I’d have three levels, like:

All Service
    argus
        InfluxDB
    cerberos
    fafnir

Based on the examples I assumed this was how to do it but I guess it’s not and I’m stumped.

Can’t do it either :cry:
(which is perhaps telling)
I’ll see how to achieve this and make some changes if need be.

1 Like

I was able to do one level of depth like this, but no further:

component: oh-list-card
config:
  accordionList: true
slots:
  default:
    - component: oh-list-item
      config:
        accordionItem: true
        title: Depth 0
        after: =1+2
      slots:
        accordion:
          - component: oh-list
            slots:
              default:
                - component: oh-list-item
                  config:
                    title: Depth 1 - Item 1
                    after: =2+3
                - component: oh-list-item
                  config:
                    title: Depth 1 - Item 2
                    after: =3+4
                - component: oh-list-item
                  config:
                    title: Depth 1 - Item 3
                    after: =4+5

2020-10-17_00-45-06

I got it working with a few limitations and some nesting :crazy_face:

  • Nested ‘icon: xy’ would work but will mess up the accordion layout a bit

// EDIT

  • I added some real items for testing now and it seems, that the ‘item’ parameter isn´t present in ‘oh-list-item’ so you have to trick around this with an expression like ‘after: =items.vArgus_Status.state’, which should also work for the badge, if you like it.

//Edit2:

  • Contrary to my statement that ‘subtitle:’ won´t work in ‘oh-label-item’ - its just depending on the ‘mediaList: true’ parameter - if set, everything works fine. :wink:

nestedAccordion

uid: nestedAccordion
tags:
  - nested
  - accordion
  - list
component: oh-list-card
config:
  title: All Services Status
  accordionList: true
  footer: Online status of home automation related services
slots:
  default:
    - component: oh-list-item
      config:
        title: All Services
        icon: oh:network_purple
        badge: " OK "
        badgeColor: green
      slots:
        accordion:
          - component: oh-list-card
            config:
              accordionList: true
              noBorder: true
              noShadow: true
              outline: true
            slots:
              default:
                - component: oh-list-item
                  config:
                    title: "argus"
                    after: =items.vArgus_Status.state
                    accordionList: true
                    noBorder: true
                    noShadow: true
                    outline: true
                  slots:
                    accordion:
                      - component: oh-label-item
                        config:
                          item: vInfluxDB_Status
                          title: "influxDB"                    
                - component: oh-label-item
                  config:
                    item: vCerberos_Status
                    title: "cerberos"
                - component: oh-label-item
                  config:
                    item: vFafnir_Status
                    title: "fafnir"
                - component: oh-list-item
                  config:
                    title: Show analysis
                    listButton: true
                    action: analyzer
                    #actionAnalyzerCoordSystem:
                    #actionAnalyzerItems:
3 Likes

Could anybody lead me in the right direction using multiple javascript functions inside of expressions - it seems that there are some particularities in the usage.

To be more accurate, I try to split and rearrange multiple variables if the value isn´t null. From what google teached me, it should work like that (with some extra brackets on the array, which seems to be one of the above mentioned particularities of the OH-expressions):

=([vars.contact.split(";")[0],vars.contact.split(";")[1],vars.contact.split(";")[2]]).filter(boolean).join(";")

This returns ‘TypeError: undefined is not a function’

If I remove the filter, everything works fine, but it adds the delimiter, even if the value is null.

=([vars.contact.split(";")[0],vars.contact.split(";")[1],vars.contact.split(";")[2]]).join(";")

Anoyone, that are more experienced in using javascript, has an idea?

Thank you!

The expression language is not actually JavaScript, it’s based on an expression parser (https://github.com/EricSmekens/jsep), so while it does resemble JavaScript code (from the jsep readme):

It can parse JavaScript expressions but not operations. The difference between expressions and operations is akin to the difference between a cell in an Excel spreadsheet vs. a proper JavaScript program.

Therefore there are a number of limitations, for instance you cannot use methods that accept functions as a parameter, like the arrays’ map or filter, because it cannot parse them.