Why is the number of my oh-repeater requests that high?

On my custom widget I try to show some state informations of my floors (group items with StateX child which is a group too). Therefore I nested two oh-repeater, the first iterates all floors (3) and the second should iterate all states (only two floors have states right now) of each floor. If I analyse the network traffic, I see each StateX item is requested five times, although I would have only expected it once. Does anyone has an idea what I’m doing wrong?

slots:
  default:
    - component: oh-repeater
      config:
        containerClasses: tabs
        fetchMetadata: ui
        for: floor
        sourceType: itemsWithTags
        itemTags: Floor
      slots:
        default:
          - component: input
            config:
              checked: =(loop.floor.metadata.ui.config.order == 0)
              id: ='tab' + (loop.floor_idx + 1)
              name: tab
              type: radio
          - component: label
            config:
              for: ='tab' + (loop.floor_idx + 1)
              style:
                order: =loop.floor.metadata.ui.config.order
            slots:
              default:
                - component: oh-icon
                  config:
                    icon: =loop.floor.category
                    style:
                      height: 42px
                      width: 42px
                      margin-top: -2px
          - component: div
            config:
              class: tab-content
              id: ='content' + (loop.floor_idx + 1)
            slots:
              default:
                - component: Label
                  config:
                    class: floor-label
                    text: =loop.floor.label
                - component: div
                  config:
                    class: state-section
                    visible: "=items['States' + loop.floor.name.substring(1)].state === '-' ?
                      'false' : 'true'"
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          for: item
                          fragment: true
                          groupItem: ='States' + loop.floor.name.substring(1)
                          sourceType: itemsInGroup
                        slots:
                          default:
                            - component: widget:hf_chip
                              config:
                                iconName: =loop.item.category
                                text: =@loop.item.name

I’m not sure what’s going on under the hood. I don’t think I’ve ever traced the oh-repeater logic all the way back to each of it’s api calls.

There’s nothing obviously suspicious about your widget construction, so it’ possible that’s just the repeater + various necessary calls of the item tracking system.

You could certainly run a few easy tests to see if this is always a function of the repeater (if it is, maybe there’s a way to better optimize some of it’s processes). I would suggest just giving a quick unique tag to one item, and setup a new widget with just a repeater pulling that unique tag. Then check to see if that very basic setup also results in 5 calls.

The other test I would run would be to put the widget you’ve got on a page and test it there as well. This very well could be some set of re-rendering loops related to the widget preview pane.

This smells like the issue we faced within the semanticHomeMenu / mainWidget project, where we faced performence issues due to using a lot of repeaters.
Solution was the introduction of

                          cacheSource: true

as config option in oh-repeater.

Even with one “Bloor” :wink: the child gets requested five times.

I already did that before; a full reload of a specific page or the preview page triggers the repetitions, a redraw in the editor results in one single request.

Did cacheSource increase the performance of your first load as well? I just added it to inner and/or outer repeater without any changes.

If I rember correct, we use it on all repeaters, as the result are somewhat static. We need them to be able to access the complete set of metadata to build the structure.
It significantly speeded up the complete rendering.

I can confirm that on a 4.3 snapshot, the repeater itself is not rendering multiple times, so all those additional calls are probably coming from secondary systems. As it seems to only happen the first time that the repeater is rendered, I strongly suspect it has to do with the mechanism that adds the repeater’s items to the list of items with state tracking.

As this was all looked at fairly carefully when cacheSource was developed, I would be surprised if multiple erroneous API calls went unnoticed, but it’s not impossible.

At any rate, to answer your original question, I don’t think it is you doing anything wrong with your widget. But If you think it’s actually impacting the performance of your OH, then it might be worth filing an issue.

In the meantime I refactored my code to only request the floors from server and all subsequent repeater iterate on parts of this first json response. As a result, my processing time dropped from about ~5s to ~540ms (16 rooms on 3 floors). I’ve not tested everything (e.g state event handling) yet, but it looks promising. As nobody else seems to have that problem I will give it a try and delay a possible issue until it bothers me again.

A bit offtopic but at least repeater related: I had the impression that one could specify tags on a itemsInGroup request, but these don’t seem to be handled on server side. Would you say that is a bug or a fragment of the itemsWithTags implementation and never meant to be used with itemsInGroup?

Your impression is correct, we used it in the mainWidget_Rollershutter:

- component: oh-repeater
  config:
      for: blindsSchedule
      sourceType: itemsInGroup
      groupItem: =props.groupItem
      fetchMetadata: semantics,metadata,widgetOrder
      filter: (loop.blindsSchedule.tags).includes("Control") && (loop.blindsSchedule.tags).includes("Timestamp") && !(loop.blindsSchedule.type=="Switch")

Sorry for the misunderstanding, my wording was a bit unclear.

If I understand your example correctly, the tag handling is local with the result of the preceding request? Would be nice if one could reduce the amount of data transfered my adding the target tags to the request itself. I tried to add the tags by setting itemTags in combination with sourceType: itemsInGroup, even if the usage is only documented for itemsWithTags. The resulting request /rest/items/MY_ITEM?metadata=undefined&tags=MY_TAGS reflects the given tags, but I had the impression that all items were still included in the response.

Ok, now I understand.
No, that is not possible. You can only use one in the repeater, itemsInGroup or itemsWitchTags.
You need to filter the result like shown in my example.
And just to make shure, using itemsWithTags is quite strict, ALL listed tag have to be present, it is not an OR combination.

Unfortunately event handling is not working 100%. Is there any chance to register for state changes by hand or do I have roll back and rely on oh-repeater for the registration?

What event handling are your referring to, item state changes? Can you provide an example of what’s not working?

Not really no. Items are added to the tracked item state list the first time they are included in a widget expression, there is no direct access to that mechanism.

You are correct, I meant state changes.

Because I changed some repeaters to work with arrays of items locally instead of re-requesting them from the server, these items don’t appear to be registered for state change notifications.

That’s a pity. Do you have a recommendation on how I can turn the JS object representation into a performant (because for the page actual unnecessary) widget expression? Alternatively, I have to go back to the server query. :frowning:

The only way in the widget expressions to dynamic item states is through the use of the items object. If you retrieved a json payload from an API call that is a static string. Yes, there is a state key for each of those items, in that json payload, but that only represents the item state at the tiem you made the call there is no link back to the OH backend.

When you use items.SomeItemName.state in a widget expression, then the named item gets added to the tracking list and item state change events that come through the SSE will be forwarded to the items object.

When you have an array of items that has been returned by a repeater then then only way to go from that to a dynamic state is to use the name key of the item array element with the items object. So,

=loop.repeaterItemArray.state <---Always static state

but

=items[loop.repeaterItemArray.name].state <---Will change in response to SSE events