F7-range not working on regular page but is working in the designer

I have the strange problem, that my f7-ranges are not working as expected. I use them in the dual configuration where min and max are item states. In the designer all ranges are drawn as expected, but on every regular page the ranges are not visible. I’ve already checked the item states and they seem to be correct (set to label on same page). When I change the min / max values to hardcoded numbers the ranges are drawn again.

I’ve read in an old thread (Dual range slider - #9 by hmerk) that hmerk faced a similar problem but it just disappeared. Does anyone else had this problem before and solved it somehow?

I cannot replicate your problem. f7-ranges work as expected. In the thread you link to the problem disappeared when other widgets on the page were reconfigured which indicates that maybe the problem was not in the f7-range to begin with. To track down your particular issue, you’re going to have to give more details. What version of OH are you on? What’s the widget code? What’s the page code?

My OH version is 4.3.3.

The widget is a modified version of semanticHomeMenu_weather:

uid: semanticHomeMenu_Weather_modified
tags:
  - v0.1
props: {}
timestamp: Mar 9, 2025, 5:04:38 PM
component: f7-card
config:
  style:
    border-radius: 10px
    margin-left: 5px
    margin-right: 5px
    min-width: 360px
  stylesheet: |
    .forecast-grid {
      display: grid;
      grid-template-columns: 30px 30px 50px 1fr 50px;
      width: 100%;
      column-gap: 20px;
    } .hourly-forecast-grid {
      display: grid;
      grid-template-rows: 20px 20px 20px;
      width: 100%;
      column-gap: 20px;
      grid-auto-flow: column;
      justify-items: center;
    } .today-grid {
      display: grid;
      grid-template:
        "station icon l_minmax minmax" 20px
        "temp icon l_wind wind" 20px
        "temp icon l_rain rain" 20px
        "temp icon a a" 20px
        "temp condition a a" 20px / 80px minmax(130px, 1fr) 140px 80px;
      align-items: stretch;
      justify-items: stretch;
      padding: 20px 20px 10px 20px;
      column-gap: 16px;
    } .today-grid > .label {
      text-align: right;
      font-size: 14px;
    } .today-grid > .value {
      text-align: left;
      font-size: 14px;
    }
slots:
  default:
    - component: div
      config:
        class: today-grid
      slots:
        default:
          - component: Label
            config:
              style:
                font-size: 16px
                grid-area: station
              text: =items.Localweatherandforecast_StationName.state
          - component: f7-icon
            config:
              f7: "=(items['OneCallAPIweatherandforecast_Current_Iconid'].state === '01d') ?
                'sun_max' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '01n') ? 'moon_stars' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '02d') ? 'cloud_sun' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '02n') ? 'cloud_moon' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '03d') ? 'cloud' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '03n') ? 'cloud' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '04d') ? 'cloud' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '04n') ? 'cloud' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '09d') ? 'cloud_heavyrain' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '09n') ? 'cloud_heavyrain' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '10d') ? 'cloud_sun_rain' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '10n') ? 'cloud_moon_rain' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '11d') ? 'cloud_sun_bolt' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '11n') ? 'cloud_moon_bolt' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '13d') ? 'cloud_snow' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '13n') ? 'cloud_snow' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '50d') ? 'cloud_fog' :
                (items['OneCallAPIweatherandforecast_Current_Iconid'].state ===
                '50n') ? 'cloud_fog' : '?'"
              size: 80
              style:
                grid-area: icon
                width: 100%
          - component: Label
            config:
              style:
                font-size: 50px
                grid-area: temp
              text: =Number.parseInt(items.OneCallAPIweatherandforecast_Current_Temperature.state)+"°"
          - component: Label
            config:
              class: label
              style:
                grid-area: l_minmax
              text: "Temperaturen:"
          - component: Label
            config:
              class: value
              style:
                grid-area: minmax
              text: =Number.parseInt(items.OneCallAPIweatherandforecast_ForecastDay0_Mintemperature.state)
                + " °C / " +
                Number.parseInt(items.OneCallAPIweatherandforecast_ForecastDay0_Maxtemperature.state)
                + ' °C'
          - component: Label
            config:
              style:
                grid-area: condition
                width: 100%
                text-align: center
              text: =items.OneCallAPIweatherandforecast_Current_Condition.state
          - component: Label
            config:
              class: label
              style:
                grid-area: l_wind
              text: "Windgeschwindigkeit:"
          - component: Label
            config:
              class: value
              style:
                grid-area: wind
              text: =@'OneCallAPIweatherandforecast_Current_Wind_Speed'
          - component: Label
            config:
              class: label
              style:
                grid-area: l_rain
              text: "Niederschlag:"
          - component: Label
            config:
              class: value
              style:
                grid-area: rain
              text: =@'OneCallAPIweatherandforecast_Current_Rain'
    - component: f7-block
      config:
        class:
          - no-padding
        style:
          margin-top: 10px
          overflow: hidden
          width: 100%
      slots:
        default:
          - component: f7-card-footer
            config: {}
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: witem
                    sourceType: range
                    rangeStart: 1
                    rangeStop: 6
                    containerClasses: hourly-forecast-grid
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                          text: =dayjs(items['OneCallAPIweatherandforecast_ForecastHours0'+loop.witem+'_Timestamp'].state).format("HH:mm")
                      - component: f7-icon
                        config:
                          f7: "=(items['OneCallAPIweatherandforecast_ForecastHours0'+loop.witem+'_Iconid'\
                            ].state === '01d') ? 'sun_max' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '01n') ?
                            'moon_stars' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '02d') ?
                            'cloud_sun' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '02n') ?
                            'cloud_moon' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '03d') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '03n') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '04d') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '04n') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '09d') ?
                            'cloud_heavyrain' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '09n') ?
                            'cloud_heavyrain' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '10d') ?
                            'cloud_sun_rain' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '10n') ?
                            'cloud_moon_rain' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '11d') ?
                            'cloud_sun_bolt' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '11n') ?
                            'cloud_moon_bolt' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '13d') ?
                            'cloud_snow' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '13n') ?
                            'cloud_snow' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '50d') ?
                            'cloud_fog' :
                            (items['OneCallAPIweatherandforecast_ForecastHours0\
                            '+loop.witem+'_Iconid'].state === '50n') ?
                            'cloud_fog' : '?'"
                          size: 25
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                          text: =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastHours0'+loop.witem+'_Temperature'].state)+"
                            °C"
    - component: f7-block
      config:
        class:
          - no-padding
        style:
          margin-top: 10px
          overflow: hidden
          width: 100%
      slots:
        default:
          - component: f7-card-footer
            config: {}
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: witem
                    sourceType: range
                    rangeStart: 1
                    rangeStop: 5
                    containerClasses: forecast-grid
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                          text: =dayjs().add(loop.witem,'day').startOf('day').format('dd')
                      - component: f7-icon
                        config:
                          f7: "=(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Iconid'].s\
                            tate === '01d') ? 'sun_max' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '01n') ? 'moon_stars'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '02d') ? 'cloud_sun'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '02n') ? 'cloud_moon'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '03d') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '03n') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '04d') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '04n') ? 'cloud' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '09d') ?
                            'cloud_heavyrain' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '09n') ?
                            'cloud_heavyrain' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '10d') ?
                            'cloud_sun_rain' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '10n') ?
                            'cloud_moon_rain' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '11d') ?
                            'cloud_sun_bolt' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '11n') ?
                            'cloud_moon_bolt' :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '13d') ? 'cloud_snow'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '13n') ? 'cloud_snow'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '50d') ? 'cloud_fog'
                            :
                            (items['OneCallAPIweatherandforecast_ForecastDay'+l\
                            oop.witem+'_Iconid'].state === '50n') ? 'cloud_fog'
                            : '?'"
                          size: 25
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                            margin-left: 10px
                          text: =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Mintemperature'].state)+"
                            °C"
                      - component: f7-range
                        config:
                          color: blue
                          disabled: true
                          dual: true
                          max: =Number.parseInt(@'maxTempForecastDays')
                          min: =Number.parseInt(@'minTempForecastDays')
                          style:
                            --f7-range-bar-bg-color: transparent
                            --f7-range-bar-size: 4px
                            --f7-range-knob-size: 0px
                          value:
                            - =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Mintemperature'].state)
                            - =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Maxtemperature'].state)
                      - component: Label
                        config:
                          style:
                            font-size: 14px
                          text: =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Maxtemperature'].state)+"
                            °C"

The page is as simple as it could be:

config:
  label: Übersicht
blocks:
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config: {}
                slots:
                  default:
                    - component: widget:semanticHomeMenu_Weather_modified
                      config: {}
masonry: []
grid: []
canvas: []

One strange addition I just recognized. Changing the OH pages and designer view etc for the code snippets, I just saw the range bars on the page on one of my browser tabs. Refreshing the page and they are gone again.

I can add another observation.
If the page is used as home page and I click on the OH logo, the bars are visible. Refresh and they are gone. Second if I navigate to the same page via http://myserver:8080/page/mypage, the bars are are never visible.

Do you see any errors in the browser developer console when you you refresh and the values don’t come up?

I can’t see any errors.

One difference I found is, that if drawn, the divs with class range-active-bar have a style with left and width set, otherwise the class style sets left to zero and width doesn’t exist.

What happens if you replace:

value:
  - =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Mintemperature'].state)
  - =Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Maxtemperature'].state)

with

value: =[Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Mintemperature'].state), Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Maxtemperature'].state)]

This should not actually make a difference, but at this point we need to do some testing to see if we can track down where an error might be occuring.

As you suspected, both variants behave the same.

I think I know what’s going here, or at least, I have a hypothesis.

Simple test:
Add the following to the witem repeater that has the f7-ranges:

key: = Math.random() + @'OneCallAPIweatherandforecast_ForecastDay1_Mintemperature' + @'OneCallAPIweatherandforecast_ForecastDay1_Maxtemperature'

More complex test:
Add label cards to a different page for OneCallAPIweatherandforecast_ForecastDay1_Maxtemperature and OneCallAPIweatherandforecast_ForecastDay1_Mintemperature. Navigate to that page and then without a refresh navigate to the page that has this widget.

I’m not entirely sure if I did everything right, but unfortunately I can’t see any difference in behavior.

Drat. But at least that gave enough information for me to finally be able to replicate the issue myself. My previous hypothesis was mostly correct, but the workaround has to be a little more direct. Add

key: =Math.random() + @'maxTempForecastDays' + @'minTempForecastDays'

Directly to the f7-range configuration.

The first time the repeater’s loop runs, the states of items referenced in the widget are not actually tracked yet so the f7-range gets undefined values for it’s min and max properties which means the library draws it as having 0 length. In 99% of cases, users don’t notice this issue with the repeater because as soon as the item states catch up, it is redrawn and everything is rendered correctly. In this case, however, there seems to be an issue with the way the f7-library is handling the updated min and max values and it requires a forced full redraw using the key property to cause it to recalculate the max and min with the correct values.

Here is how I added the line:

- component: f7-range
  config:
    color: blue
    disabled: true
    dual: true
    key: =Math.random() + @'maxTempForecastDays' + @'minTempForecastDays'
    max: =Number.parseInt(@'maxTempForecastDays')
    min: =Number.parseInt(@'minTempForecastDays')
    style:
      --f7-range-bar-bg-color: transparent
      --f7-range-bar-size: 4px
      --f7-range-knob-size: 0px
    value: =[Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Mintemperature'].state),
      Number.parseInt(items['OneCallAPIweatherandforecast_ForecastDay'+loop.witem+'_Maxtemperature'].state)]

Your explanation sounds plausible, but unfortunately the change hasn’t helped yet. I’m confused that it worked for you but not for me. Could I have done something else wrong?

That’s strange. It doesn’t look like you’ve done anything wrong. Other than the fact that I have to change the item names because I don’t have those forecast items, that code you’ve posted is the same as my test version which does not have the problem. I’m on a 5.0 snapshot, not 4.3.3, but the neither the repeater nor the f7-range has changed between those versions.

What browser are you using?

I’ve tested it with Chrome and Firefox.

Chrome should work, that’s what I’m using.

When you reload the page are you reloading (Ctrl + r) or hard reloading (Ctrl + Shift + r)? If you are just doing the regular reload, try the hard reload, or even better, long press on the reload button on the menu bar until you get the “Empty Cache and Hard Reload” option.

If that doesn’t work, then you’ve got some extra ghost in the machine…I suppose you could try an OH restart as well.

But, if it were me, I would find it faster to build another solution than try and trace down whatever obscure cache problem is causing this. Because you are not using the actual interaction feature of the range bar, you are really just creating one transparent div with a second smaller colored div inside. Getting that pair of divs to look just like the f7 range would be the matter of looking at the actual f7 range elements and adding the correct classes (probably just some combination of range-slider, range-bar, and range-bar-active, but there may be a few others as well. The only tricky part is that you’d have to do the calculations for the width of the colored bar yourself based on the items, but this could be streamlined with an oh-context.

Both ways without luck.

I think that will be the way I’m going to take. Do you know any good/complete oh-context examples? I tried a few times to use variables, but they never worked for me.

Either way, thank you very much for your effort and your help!

In this case you don’t want variables, you want functions which greatly simplifies the expression when reusing some more complex calculations. For this you probably want something like this:

- component: oh-context
  config:
    functions:
      leftPos: =(val, min, max) => ( val - min ) / ( max - min ) * 100 + '%'
      barWidth: =(upper, lower, min, max) => (upper - lower) / (max - min) * 100 + '%'
  slots:
    default:
      - component: div
        config:
          style:
            border: 1px solid black
            width: 100%
            height: 10px
            position: relative
        slots:
          default:
            - component: div
              config:
                style:
                  position: absolute
                  background: blue
                  left: =fn.leftPos(60, 50, 100)
                  width: =fn.barWidth(75,60,50,100)
                  height: 100%