openHAB 3 UI - custom widget - oh-repeater for array

Hello,
i tried hard but

  1. could not find examples
  2. could not get it running by myself

If i have a item

String                     lTim_Str

with the value: “string1;string2”

Is it possible to make a custom widget with oh-repeater to have one oh-list-item for each string?
As you sure can see i wanted to use semicolon as delimiter → Changing the string by adding more strings, divided by “;” shall automatically add oh-list-items to the widget

I thought may could use the .spllit(";") operation to generate an array from this string directly within the widget definition

uid: listLogTasks
tags:
  - repeater
  - list
  - log
  - tasks
timestamp: Jun 4, 2021, 8:45:07 PM
component: oh-list-card
config:
  title: Tasks
  slots:
    default:
      - component: oh-repeater
        config:
          for: i
          source: array
          in: =items[lTim_Str].state.split(";")
          fragment: true
        slots:
          default:
            - component: oh-list-item
              config:
                icon: f7:lightbulb
                title: OneLine

Your array is actually probably working just fine. I have widgets where I use split() for exactly this purpose in a repeater. I suspect the problem is that your widget is not rendering properly because your YAML isn’t quite lined up right.

The slots for the oh-list-card should be in line with the config and everything below that should move in one indent accordingly:

component: oh-list-card
config:
  title: Tasks
slots:
  default:
    - component: oh-repeater
3 Likes

Yes you are right!

i made two errors:

  1. i used “source” instead of “sourceType”
  2. The arrangement was not correct (as you said → sorry for this beginner failure)

This is the code now:

uid: listLogTasks
tags:
  - repeater
  - list
  - log
  - tasks
timestamp: Jun 4, 2021, 8:45:07 PM
component: oh-list-card
config:
  title: Tasks
slots:
  default:
    - component: oh-repeater
      config:
        for: i
        sourceType: array
        in: =items[lTim_Str].state.split(";")
        fragment: true
      slots:
        default:
          - component: oh-list-item
            config:
              icon: f7:lightbulb
              title: =items[lTim_Str].state.split(";").get(1)

But it seems like i’m still having problems.

Now i have changed the value of lTim_Str to “day1;day2;day3”
→ So i should generate 3 list-items because of the three strings inbetween the semicolons, but it generates only one

Here how it looks right now:

You also have an error in how you are using the items object. There are two ways to reference the various items available in that object. One is a direct reference to the key in the object that is the item’s name; this way doesn’t use any quotes:

items.exactItemName.state

The second way uses brackets for an indirect reference which allows you to reference keys using string variables or other indirect methods. That means, however, that if you are going to use the item name within the brackets you have to put that item name within quotes to make it a string:

items["exactItemName"].state

So you either need to put quotes around lTim_Str in the two places where it is inside the brackets or just use the direct method.

1 Like

Oh YESSS!!
Sorry for my failure!

You made my day :wink:

So to finish this up,
with great help from @JustinG i got the first part of my todo-widget for “house tasks” done.

out

Purpose is, that i have arrays for

  1. Timestamp (in front of -)
  2. Topic (Badges)
  3. Bandge-Colors
  4. Text (after -)
  5. Item, storing which line was klicked → the clicked one can thenn be deleted via the red button
  6. In the background also custom action shall be settable to maybe direcly get to the relevant site for each message

This way every function can create messages which are important and they can be handled.
Number of Tasks is flexible, due to the fact, that the information is stored in Semicolon-separated Strings

I just wanted to leave the now partially done code for others, trying to do similar things

uid: listLogTasks
tags:
  - repeater
  - list
  - log
  - tasks
timestamp: Jun 4, 2021, 8:45:07 PM
component: oh-list-card
config:
  title: Offene Aufgaben
slots:
  default:
    - component: oh-list-item
      config:
        action: rule
        listButton: true
        listButtonColor: red
        title: Löschen
        color: red
    - component: oh-repeater
      config:
        for: int
        sourceType: array
        in: =items["lTim_Str"].state.split(";")
        fragment: true
      slots:
        default:
          - component: oh-list-item
            config:
              icon: '=(items["lDel_Num"].state == loop.int_idx) ? "f7:checkmark_alt_circle_fill" : "f7:circle"'
              title: =items["lTim_Str"].state.split(";")[loop.int_idx] + ' - ' + items["lTxt_Str"].state.split(";")[loop.int_idx]
              badge: =items["lTop_Str"].state.split(";")[loop.int_idx]
              badgeColor: =items["lCol_Str"].state.split(";")[loop.int_idx]
              listButton: false
              action: command
              actionItem: lDel_Num
              actionCommand: '=(loop.int_idx == "") ? "0" : loop.int_idx'

NOTE: For loop.int_idx the behaviour for index 0 was strange → I had to catch this one by using the syntax
actionCommand: '=(loop.int_idx == "") ? "0" : loop.int_idx'

2 Likes

OK so now just the last update:
I now changed this Widget to be a List/Card “House Tasks and Notifications” Widget

Here a short overview
output

Features, the cards can be handled:

  • Set Title
  • Set Topic (Badge)
  • Set Color (Badge + Icon)
  • Set Icon
  • Set footer = Time, related to the task
  • Set Action

For Action to set there are possibilties

  1. Set no action → Blue Button will not be shown
  2. Set action → Various actions possible (command, navigate, etc.)

Over all:
This is the way i wanted a Task-System for the house to be
Each Source-Rule/Function can attach new Strings to the current Items and this automatically creates a new Task widget with super individual configuration possibilities

Examples:

  • Error in the system → Action button shall navigate to a page of openHAB 3 UI
  • Weather warning → Action button shall open www.weather.com

Im not a very advanced user so there will surely be things i did not code in a perfect way → If someone sees optimization possibilities → Feel free to let me know

For me this is a custom Task-function i love because everyone in the house can see and manage these tasks and i dont need a external service for it.

I will also integrate a push-notification through the app, in case a new message is added.

If this helps others ill leave the code below

uid: listLogTasks
tags:
  - repeater
  - list
  - log
  - tasks
timestamp: Jun 6, 2021, 3:11:23 PM
component: oh-repeater
config:
  for: int
  sourceType: array
  in: =items["lTim_Str"].state.split(";")
  fragment: true
slots:
  default:
    - component: oh-list-card
      config:
        footer: =items["lTim_Str"].state.split(";")[loop.int_idx]
        visible: =items["lTxt_Str"].state.split(";")[loop.int_idx] !== ""
      slots:
        default:
          - component: oh-list-item
            config:
              icon: =items["lIco_Str"].state.split(";")[loop.int_idx]
              title: =items["lTxt_Str"].state.split(";")[loop.int_idx]
              badge: =items["lTop_Str"].state.split(";")[loop.int_idx]
              badgeColor: =items["lCol_Str"].state.split(";")[loop.int_idx]
              iconColor: =items["lCol_Str"].state.split(";")[loop.int_idx]
              accordionList: true
          - component: oh-list-item
            config:
              title: =items["lActTxt_Str"].state.split(";")[loop.int_idx]
              listButton: true
              action: =items["lAct_Str"].state.split(";")[loop.int_idx]
              actionPage: =items["lActTar_Str"].state.split(";")[loop.int_idx]
              actionCommand: =items["lActCom_Str"].state.split(";")[loop.int_idx]
              actionItem: =items["lActItm_Str"].state.split(";")[loop.int_idx]
              visible: =items["lAct_Str"].state.split(";")[loop.int_idx] !== "NULL"
          - component: oh-list-item
            config:
              title: Löschen
              listButton: true
              color: red
              action: command
              actionItem: lDel_Num
              actionCommand: '=(loop.int_idx == "") ? "0" : loop.int_idx'
// ========================================================
// LOGGING TASKS
// ========================================================


rule "Logging Task Delete"
when
    Item lDel_Num changed
then

    // If a valid item number to delete was set
    if (lDel_Num.state >= 0){

        logInfo("LOGGINGTASK", "Task #" + lDel_Num.state +" erased")

        // Declarate temp Strings
        var String lTim_Str_tmp = ""
        var String lTop_Str_tmp = ""
        var String lCol_Str_tmp = ""
        var String lTxt_Str_tmp = ""
        var String lIco_Str_tmp = ""
        var String lAct_Str_tmp = ""
        var String lActCom_Str_tmp = ""
        var String lActItm_Str_tmp = ""
        var String lActTar_Str_tmp = ""
        var String lActTxt_Str_tmp = ""

        // Get number of items
        var Number len = lTxt_Str.state.toString.split(";").length

        // Set numerator
        var Number i = 0

        // Loop through elements
        while (i< len) {

            // Do not copy the part which is to delete
            if (lDel_Num.state as Number != i){
                
                 // Copy Task if it shall not be deleted
                lTim_Str_tmp = lTim_Str_tmp + lTim_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lTop_Str_tmp = lTop_Str_tmp + lTop_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lCol_Str_tmp = lCol_Str_tmp + lCol_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lTxt_Str_tmp = lTxt_Str_tmp + lTxt_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lIco_Str_tmp = lIco_Str_tmp + lIco_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lAct_Str_tmp = lAct_Str_tmp + lAct_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lActCom_Str_tmp = lActCom_Str_tmp + lActCom_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lActItm_Str_tmp = lActItm_Str_tmp + lActItm_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lActTar_Str_tmp = lActTar_Str_tmp + lActTar_Str.state.toString.split(";").get(i.intValue).toString + ";"
                lActTxt_Str_tmp = lActTxt_Str_tmp + lActTxt_Str.state.toString.split(";").get(i.intValue).toString + ";"
 
           }

            logInfo("LOGGINGTASK", lTim_Str_tmp)
            // Increase numerator
            i = i + 1

        }

        // Update Log Items
        lTim_Str.sendCommand(lTim_Str_tmp)
        lTop_Str.sendCommand(lTop_Str_tmp)
        lCol_Str.sendCommand(lCol_Str_tmp)
        lTxt_Str.sendCommand(lTxt_Str_tmp)
        lIco_Str.sendCommand(lIco_Str_tmp)
        lAct_Str.sendCommand(lAct_Str_tmp)
        lActCom_Str.sendCommand(lActCom_Str_tmp)
        lActItm_Str.sendCommand(lActItm_Str_tmp)
        lActTar_Str.sendCommand(lActTar_Str_tmp)
        lActTxt_Str.sendCommand(lActTxt_Str_tmp)


        // Reset Delete Indicator
        lDel_Num.sendCommand(-1)

    }

end

rule "Logging Task Test"
when
    Item tTst_Swt changed from OFF to ON
then

    // Define Dummy Arrays
    val String aTim = "21.05.2021;Dienstag;Mittwoch;"
    val String aTop = "Fehler;Abfall;Wetter;"
    val String aTxt = "Heizung - Kreislauf 1 Druck zu hoch;Biomüll;Gewitter;"
    val String aCol = "red;green;yellow;"
    val String aAct = "navigate;NULL;navigate;"
    val String aActCom = "NULL;NULL;NULL;"
    val String aActItm = "NULL;NULL;NULL;"
    val String aActTar = "page:buero;NULL;page:buero;"
    val String aActTxt = "Detail;NULL;Gehe zu weather.com;"
    val String aIco = "f7:exclamationmark_circle_fill;f7:archivebox;f7:cloud;" 

    // Set Values
    lTim_Str.sendCommand(aTim)
    lTop_Str.sendCommand(aTop)
    lTxt_Str.sendCommand(aTxt)
    lCol_Str.sendCommand(aCol)
    lAct_Str.sendCommand(aAct)
    lActCom_Str.sendCommand(aActCom)
    lActItm_Str.sendCommand(aActItm)
    lActTxt_Str.sendCommand(aActTxt)
    lIco_Str.sendCommand(aIco)
    lActTar_Str.sendCommand(aActTar)
    lDel_Num.sendCommand(-1)

end