Using swiper to change variable in widget

I’m using a great widget by Marcus that can display grafana graphs in a oh-webframe (Grafana chart with time ranges).
I’d like to add a swiper so I can change the charts timerange backwards/forwards in time.

I’ve modified the widget so that it shows different graphs depending on the buttons at the buttom of the widget - when the buttons are pressed a new url is loaded with the corresponding graph that shows a given time period (day, week, month year).

Here is the widget code as it is seen above:

uid: Grafana chart with timeranges v4
tags: []
props:
  parameters:
    - description: Title of the chart
      label: Title
      name: title
      required: false
      type: TEXT
    - description: URL to show in the frame
      label: Source URL
      name: URL
      required: true
      type: TEXT
    - default: from=now-0d%2Fd-1h&to=now-0d%2Fd&viewPanel=3&kiosk;Day,viewPanel=6&kiosk;Week,viewPanel=7&kiosk;Month,viewPanel=8&kiosk;Year
      description: Comma-separated List of options. Example "from=now-6h&to=now;-6h,viewPanel=3&kiosk;Day" for past "6h" and "Today so far". First entry is default.
      label: Time range options
      name: timerange
      required: true
      type: TEXT
    - description: Height of the Frame (empty = default)
      label: Height
      name: height
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Jun 18, 2023, 9:53:36 AM
component: f7-card
config:
  outline: true
  style:
    --f7-card-margin-horizontal: 10px
    --f7-card-margin-vertical: 3px
    --f7-card-padding-horizontal: 10px
    --f7-card-padding-vertical: 100px
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.3)
    margin-bottom: 10px
    margin-top: 10px
    noShadow: false
  title: =props.title
slots:
  default:
    - component: oh-webframe-card
      config:
        borders: false
        class:
          - display-block
        height: =props.height
        noBorder: false
        noShadow: true
        src: =props.URL.replace('{period}', vars.selectedPeriod || [props.timerange.split(',')[0].split(';')[0]])
    - component: f7-segmented
      config:
        class:
          - padding-bottom-half
        outline: false
        round: false
        style:
          --f7-button-border-radius: 4px
          --f7-button-font-size: 14px
          --f7-button-font-weight: 300
          --f7-button-outline-border-width: 1px
          --f7-button-padding-horizontal: 0px
          --f7-button-padding-vertical: 0px
          --f7-button-text-color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
          --f7-button-text-transform: none
          margin-left: 10px
          margin-right: 10px
      slots:
        default:
          - component: oh-repeater
            config:
              for: size
              fragment: true
              sourceType: range
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: period
                    fragment: true
                    in: =[props.timerange.split(",")[loop.size].split(";")[1]]
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: variable
                          actionVariable: selectedPeriod
                          actionVariableValue: =props.timerange.split(",")[loop.size].split(";")[0]
                          fill: "=(([props.timerange.split(',')[loop.size].split(';')[0]] == vars.selectedPeriod) || (props.timerange.split(',')[0].split(';')[1] === loop.period) && !vars.selectedPeriod) ? true : false"
                          outline: true
                          round: false
                          style:
                            --f7-button-border-color: var(--f7-card-outline-border-color)
                          text: =loop.period

To change these the base url is the same, the only change is the timerange and panel id which looks like the following:

from=now-0d%2Fd-1h&to=now-0d%2Fd&viewPanel=3&kiosk

The only thing I need to add is a swiper, that when the arrows are pressed increment/decrement the variable highlighted in the quote above “0
So initially the daily powerconsumption for today is shown, then i press the left arrow and the new url should be

from=now-1d%2Fd-1h&to=now-1d%2Fd&viewPanel=3&kiosk

I’ve read alot on the forums about variables and seen defineVars and =vars.xx in oh-repeaters, but what the right tool to use and how to implement this so they change part of the props.URL I’m really struggling with, especially since what I need to change is itself in part of a {period} variable

I hope someone can help and point me in the right direction.

Cheers

You cannot use the swiper component to do this. The functions of the swipers arrow buttons are internal to it only and can’t be repurposed by OH. You can, however, easily add your own buttons with arrows (or whatever text or image you’d like) using the oh-button component.

Variables are the correct way to handle this situation:

and with the oh-button setting the value of a variable is as easy as giving the button the variable action:

For this I would use the js string replaceAll function in the same way you are already using replace for the period. But now you’re replacing every instance of something like {range} in the timerange property with the value of a variable that you can increment and decrement with oh-buttons.

Sorry to revive this thread, but I’m looking into variables again, with the same widget, and I’m having an issue implementing the logic to get my buttons working correctly.

I’m using 2 variables, is there a way to change both variables using a button and the actionVariableValue Action?

There is another option but if the above is doable then that would be the easiest way.

The other is to make 2 buttons control the same variable, but this variable has several classes/methods (i think they would be called?) - but they are used as “subvariables”, and then could i make a sP.pIdx and only change that value using another button?

- component: oh-button
                        config:
                          action: variable
                          actionVariable: sP
                          actionVariableValue: "= {'period': props.rangePanels.split(',')[loop.size].split(';')[0], 'count': props.rangePanels.split(',')[loop.size].split(';')[2], index: loop.size }"

these are used to construct the URL:

- component: oh-webframe-card
                  config:
                    height: =props.height
                    src: = props.URL.replace('{period}', (vars.sP?.period || props.rangePanels.split(',')[props.rangeDefault].split(';')[0]) .replaceAll('{frange}', ((((vars.sP?.count || 0)*(vars.pIdx || 0))+1) || 1)) .replaceAll('{trange}', (((vars.sP?.count || 0)*(vars.pIdx || 0)) || 0)))

I have tried both, but my efforts didn’t pay off…

No, an action can only do one thing at a time, but there is a work around:

In the workaround, you mention

If you’re setting more than one variable then maybe it’s easier to make that variable an object with multiple keys

Is that what is going on here?

action: variable
actionVariable: sP
actionVariableValue: "= {'period': props.rangePanels.split(',')[loop.size].split(';')[0], 'count': props.rangePanels.split(',')[loop.size].split(';')[2], index: loop.size }"

Is it then possible, in another button to adress only a specific key of the variable?
And is there a reasonable limit to how many keys a variable can have? I mean if it is like 255 or something then that limit is likely never reached, but if it is maybe 5 or 8, then perhaps in some scenario that is handy to know.

Cheers for taking your time to spread wisdom :metal:

Yes. Under the hood, yaml is actually just a human readable syntax for JSON objects. So, you can represent an object with multiple keys in two different ways. You can set the value to a JSON object string directly as in the example above or you can do the exact same thing in yaml format:

actionVariableValue:
  period: =props.rangePanels.split(',')[loop.size].split(';')[0]
  count: =props.rangePanels.split(',')[loop.size].split(';')[2]
  index: =loop.size

Yes once the variable is an object then you can reference its keys anywhere you can use the variable. From the example above you would just use:

vars.sP.period

Only the limitations imposed by the bandwidth and processing power of your system. You are just creating javascript objects that exist within the running javascript process of the browser.

Hey Champ

Just wanted to say lots of thanks for your help!!
And this is the finished product:

OH_Grafana

I really appreciate you taking the time to make me learn these things :beers:

BR
Mark