OH3 - Expandable F7-card

Hello,
I built my first expandable f7-card, which works almost as expected.
However I need your help to sort out some points:

  1. I’m not sure the approach I use to expand the card is correct. I suppose the design can be simplified and improved. I guess the css classes are not used properly.

  2. The items aligned on the right site of the card (Gauge and Grass Icon) are not at the right position when the card is collapsed again

Correct - before the card was expanded:

Wrong: after the card was closed: The Icon and Gauge moved out the visible area.

  1. The icon to close the expanded card does not work and is stretched :frowning:

Thanks for any hint :slight_smile:

Below is the code I use - still with dummy item entries for testing.

uid: widget_Bewaesserung_v1-3
tags: []
props:
  parameters:
    - description: A text prop
      label: Prop 1
      name: prop1
      required: false
      type: TEXT
    - context: item
      description: An item to control
      label: Item
      name: item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Mar 13, 2021, 6:56:54 PM
component: f7-card
config:
  expandable: true
  swipeToClose: true
  backdrop: true
  class:
    - no-padding
  style:
    height: 200px
    margin: 10px
    box-shadow: var(--f7-card-expandable-box-shadow)
slots:
  default:
    - component: oh-button
      config:
        iconF7: gear
        iconSize: 30px
        color: black
        style:
          position: absolute
          top: 0
          right: 0
          padding-top: 10px
          padding-bottom: 35px
          z-index: 999
        class:
          - cell-open-button
          - card-opened-fade-out
          - float-right
    - component: oh-button
      config:
        iconF7: xmark_circle_fill
        iconSize: 30px
        color: black
        style:
          position: absolute
          top: 0
          right: 0
          padding-top: 10px
          padding-bottom: 35px
          z-index: 999
        class:
          - card-opened-fade-in
          - cell-close-button
          - float-right
    - component: oh-link
      config:
        action: toggle
        actionItem: Bewaesserung_Rasen_Schalter
        actionCommand: ON
        actionCommandAlt: OFF
        class:
          - card-prevent-open
        style:
          width: 100%
          height: 200px
          position: absolute
          top: 0
          left: 0
          z-index: 0
    - component: f7-card-content
      config:
        style:
          width: 100%
      slots:
        default:
          - component: f7-icon
            config:
              material: grass
              size: 80px
              color: green
              style:
                position: absolute
                right: 3%
                top: 120px
                opacity: 40%
          - component: f7-block
            config:
              style:
                margin: 0px
                height: 200px
            slots:
              default:
                - component: f7-row
                  config:
                    class:
                      - display-flex
                      - align-items-center
                      - justify-content-space-between
                    style:
                      white-space: nowrap
                      flex-wrap: nowrap
                      height: 75px
                      weight: 100%
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            height: 75px
                            width: auto
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-flex-start
                        slots:
                          default:
                            - component: Label
                              config:
                                text: Büsche hinten
                                style:
                                  font-size: 25px
                                  font-weight: 600
                            - component: f7-chip
                              config:
                                text: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? 'Bewässerung aktiv' : 'AUS'"
                                color: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? 'green' : 'gray'"
                      - component: f7-col
                        config:
                          style:
                            margin-top: 15px
                            width: auto
                          class:
                            - display-flex
                            - flex-direction-column
                        slots:
                          default:
                            - component: oh-gauge
                              config:
                                min: 0
                                max: 90
                                type: semicircle
                                value: 40
                                labelText: 20 min
                                borderWidth: 20
                                size: 100
                                borderBgColor: "#d2d2d2"
                                borderColor: "#4287f5"
                                visible: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? true : false"
                                style:
                                  width: 100%
                - component: f7-row
                  config:
                    style:
                      white-space: nowrap
                      flex-wrap: nowrap
                      height: 30px
                      width: 16%
                    class:
                      - display-flex
                      - flex-direction-row
                      - align-items-flex-start
                      - justify-content-flex-start
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud_rain
                          size: 20px
                          color: gray
                          visible: "=items.Bewaesserung_Rasen_Regenautomatik.state === 'ON' ? true : false"
                          style:
                            padding-right: 5px
                      - component: f7-icon
                        config:
                          f7: umbrella
                          size: 20px
                          color: gray
                          visible: "=Number.parseInt(items.item_Netatmo_Regen_Niederschlag.displayState) >= 1 ? true : false"
                          style:
                            padding-right: 5px
                - component: f7-row
                  config:
                    style:
                      flex-wrap: nowrap
                      height: 10px
                      width: 180px
                    class:
                      - display-flex
                      - flex-direction-row
                      - align-items-flex-start
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            width: 40%
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-center
                        slots: {}
                - component: f7-row
                  config:
                    style:
                      margin-top: 10px
                      align-content: flex-end
                      height: 50px
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            flex-wrap: nowrap
                            width: 100%
                            align-content: flex-start
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-flex-start
                        slots:
                          default:
                            - component: f7-row
                              config:
                                style:
                                  flex-wrap: nowrap
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: alarm
                                      size: 20px
                                      color: blue
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-top: 0px
                                  - component: Label
                                    config:
                                      text: 19. April, 18:30
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-left: 5px
                                        font-size: 14px
                                        font-weight: 600
                                  - component: f7-icon
                                    config:
                                      f7: timer
                                      size: 20px
                                      color: blue
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-top: 0px
                                        margin-left: 10px
                                  - component: Label
                                    config:
                                      text: 35min
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-left: 5px
                                        font-size: 14px
                                        font-weight: 600
                            - component: f7-row
                              config:
                                style:
                                  margin-top: 5px
                                  flex-wrap: nowrap
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      material: restore
                                      color: gray
                                      size: 18px
                                      style:
                                        margin-top: 0px
                                        margin-left: 0px
                                  - component: Label
                                    config:
                                      text: 14. April, 18:30
                                      style:
                                        margin-left: 8px
                                        font-size: 12px
                                        color: gray
                                  - component: f7-icon
                                    config:
                                      f7: timer
                                      size: 15px
                                      color: gray
                                      style:
                                        margin-top: 2px
                                        margin-left: 10px
                                  - component: Label
                                    config:
                                      text: 20min
                                      style:
                                        margin-left: 3px
                                        font-size: 12px
                                        color: gray
          - component: f7-block
            config:
              class:
                - card-prevent-open
                - card-content-padding
              style:
                height: 300px
            slots:
              default:
                - component: oh-list
                  config:
                    class:
                      - padding
                  slots:
                    default:
                      - component: oh-stepper-item
                        config:
                          title: Ausschalt Timer (min)
                          item: Bewaesserung_Rasen_Ausschalt_Timer
                          icon: f7:timer
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: Label
                        config:
                          text: =props.Title?props.Title:"Timer Settings"
                          style:
                            padding: 7px
                            border-bottom: 1px solid grey
                            font-weight: 600
                            color: gray
                            margin-top: 10px
                      - component: oh-toggle-item
                        config:
                          title: Timer
                          icon: f7:alarm
                          color: green
                          item: Bewaesserung_Rasen_Timer
                      - component: oh-input-item
                        config:
                          title: Startzeit
                          type: datepicker
                          sendButton: true
                          item: Bewaesserung_Rasen_Timer_Startzeit
                          outline: false
                          calendarParams:
                            timePicker: true
                            dateFormat:
                              month: short
                              day: numeric
                              hour: numeric
                              minute: numeric
                          style:
                            --f7-input-bg-color: "#ededed"
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Timer_Laufzeit
                          title: Laufzeit (min)
                          icon: f7:timer
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Interval
                          title: Interval (Tage)
                          icon: f7:arrow_2_circlepath
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: Label
                        config:
                          text: =props.Title?props.Title:"Wettersteuerung"
                          style:
                            padding: 7px
                            border-bottom: 1px solid grey
                            font-weight: 600
                            color: gray
                            margin-top: 10px
                      - component: oh-toggle-item
                        config:
                          title: Regenautomatik
                          icon: f7:cloud_rain
                          color: green
                          item: Bewaesserung_Rasen_Regenautomatik
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Regenautomatik_Grenzwert
                          title: Grenzwert Regen (mm)
                          icon: f7:chart_bar
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90

3 Likes

strange behaviour indeed. I see you are working with some absolute positions, maybe that is causing the issues. You also could consider to use popup instead of expandable card.

anyway, a very nice widget. i have a watering system in my garden as well and need to start working on a widget soon :slight_smile: as spring is arriving soon . I see you are handling with “Grenzwert” on rain? how are you including this, i suspect in a rule? What is your measurement here?

Hello Jan,

I guess the positioning issue could be related to this comment from @ysc .
However I’m not sure how to solve it.

I implemented the “rain automatic” feature in my watering system last year in OH2.5 using old DSL rules.
I use the data from Netatmo for old/current rain and OpenWheather Binding for forecasts.
With this I calculated whether I can decrease the water in case of less rain, or skip the watering at all.
I set a watering interval (e.g. every 5 days) and rain threshold (e.g. 10mm).
At the scheduled watering time I checked the rain in the past 24hrs, 3days, days set as interval. In case the total volume of rain was exceeded the threshold, then I rescheduled the watering by 1 day.
The next day I did the same check, and so on. Once the rain volume was lower than threshold, I start watering, if no rain was forecasted. (taken the amount to forecasted rain into account).

This worked very well in OH2.5, but now I need to migrate this to OH 3.0 - but now using Phyton script.

Hi Stefan, i dont think this is related as the comment from @ysc was related to a OH-CELL which has some additional slots pre-defined to make standard widget building for simple use cases easier.

The f7 card is more flexible. I will have a look into some of my widgets and see if i can draw some conclusions why this happens in your example.

thanks for shedding some light into your strategy to determine watering. i have been working with Netatmo, openweathermap data etc. but was not entirely happy yet. i might come back for some more advise. :slight_smile:

Hi Jan,

I did some further checks and was able to reproduce the issue on my laptop as well.
I highlighted interesting part but I have no explanation for it.
Not sure why the value in content width is not 100% anymore, but disappeared in the code.

It seems the width after the card is collapsed again is equal to the total screen size.
You can see in the last screenshot that the grass icon is set outside the visible screen and completely disappeared.

Hi Stefan,

what i see in your widget is that you have placed all content with “absolute” positioning, everything what goes in expanded is nicely in rows and colums. i believe this is the root cause. This does not explain why the position absolute is disapearing, but as a test if you just remove the absolute element from the gras, it obviously will be re-positioned like everything else ( as absolute is related to each other ), but if you do the test then with expanding and colapsing, the gras is still there where it was. I believe to sort the problem, you need to work in rows and colums to properly position the elements within the card-content part of the widget unless someone has another solution.

There is a nice discussion in another post around this topic of placement, this might eventually help:

Hi Jan,

the absolute position is already a workaround I use.
Initially I used a f7-col with flex-end alignment.
This was not working either, as the width of the card is not correct once collapsed.

EDIT: the position is correct, when I move the icon in the content-header.
However in this case the icon length is stretched -same as the close icon in point 3) in the initial question.

looping in @RGroll who might have an idea of what is going on with this? Sorry Rainer to put you on the spot :slight_smile:

Hey @stefan13 and @muelli1967

first of all, nice widget!


This behavior is mentioned in the docs here.

Expandable card content (card-content ) is set to 100vw width when collapsed (closed). It is done to improve card open/close transition performance, so you need to take care about its content positioning. You can make its content width also animatable and responsive by adding additional card-expandable-animate-width class to card element, but performance can be worse in this case.

The 100vw width will overwrite the applied styling on the card-content component after the first expansion of the card. Performance seems okay for me after adding the mentioned class, which would be the easiest soloution for your case, I think.


The expand transformation will applied for each element outside of card content-elements (card-header, card-content, card-footer) which leads to the stretched icon - so it’s needed that any visible element for the opened card is inside these card content-elements.


I had a quick look at your widget and done some small optimizations to the mentioned problems - but only for the ones that were obvious at a first glance, so its worth checking all components again.

YAML
uid: widget_Bewaesserung_v1-3
component: f7-card
config:
  expandable: true
  swipeToClose: true
  backdrop: true
  class:
    - card-expandable-animate-width
  style:
    height: 200px
    width: auto
slots:
  default:
    - component: oh-button
      config:
        iconF7: gear
        iconSize: 30px
        color: black
        style:
          position: absolute
          top: 0
          right: 0
          padding-top: 10px
          padding-bottom: 35px
          z-index: 999
        class:
          - cell-open-button
          - card-opened-fade-out
    - component: f7-card-content
      config:
        style:
          width: 100%
      slots:
        default:
          - component: f7-icon
            config:
              material: grass
              size: 80px
              color: green
              style:
                opacity: 40%
                position: absolute
                top: 120px
                right: 16px
          - component: oh-button
            config:
              iconF7: xmark_circle_fill
              iconSize: 30px
              color: black
              style:
                position: absolute
                top: 0
                right: 0
                padding-top: 10px
                padding-bottom: 35px
                z-index: 999
              class:
                - card-opened-fade-in
                - cell-close-button
                - card-close
          - component: oh-link
            config:
              action: toggle
              actionItem: Bewaesserung_Rasen_Schalter
              actionCommand: ON
              actionCommandAlt: OFF
              class:
                - card-prevent-open
              style:
                width: 100%
                height: 100%
                position: absolute
                top: 0
                left: 0
                z-index: 0
          - component: f7-block
            config:
              class:
                - no-padding
              style:
                margin: 0px
                height: 200px
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      height: 75px
                      white-space: nowrap
                      flex-wrap: nowrap
                  slots:
                    default:
                      - component: f7-col
                        slots:
                          default:
                            - component: Label
                              config:
                                text: Büsche hinten
                                style:
                                  font-size: 25px
                                  font-weight: 600
                                  text-overflow: ellipsis
                                  overflow: hidden
                                  white-space: nowrap
                            - component: f7-chip
                              config:
                                text: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? 'Bewässerung aktiv' : 'AUS'"
                                color: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? 'green' : 'gray'"
                      - component: f7-col
                        config:
                          style:
                            width: auto
                        slots:
                          default:
                            - component: oh-gauge
                              config:
                                min: 0
                                max: 90
                                type: semicircle
                                value: 40
                                labelText: 20 min
                                borderWidth: 20
                                size: 100
                                borderBgColor: "#d2d2d2"
                                borderColor: "#4287f5"
                                visible: "=items.Bewaesserung_Rasen_Schalter.state === 'ON' ? true : false"
                                style:
                                  margin-right: 15px
                                  margin-top: 15px
  
                - component: f7-row
                  config:
                    style:
                      white-space: nowrap
                      flex-wrap: nowrap
                      height: 30px
                    class:
                      - justify-content-flex-start
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: cloud_rain
                          size: 20px
                          color: gray
                          visible: "=items.Bewaesserung_Rasen_Regenautomatik.state === 'ON' ? true : false"
                          style:
                            margin-right: 5px
                      - component: f7-icon
                        config:
                          f7: umbrella
                          size: 20px
                          color: gray
                          visible: "=Number.parseInt(items.item_Netatmo_Regen_Niederschlag.displayState) >= 1 ? true : false"
                          style:
                            margin-right: 5px
                - component: f7-row
                  config:
                    style:
                      height: 66px
                      width: 100%
                      overflow: hidden
                  slots:
                    default:
                      - component: f7-col
                        config:
                          style:
                            flex-wrap: nowrap
                            align-self: flex-end
                        slots:
                          default:
                            - component: f7-row
                              config:
                                class:
                                  - justify-content-flex-start
                                style:
                                  flex-wrap: nowrap
                                  width: 100%
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: alarm
                                      size: 20px
                                      color: blue
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-top: 0px
                                  - component: Label
                                    config:
                                      text: 19. April, 18:30
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        text-overflow: ellipsis
                                        overflow: hidden
                                        white-space: nowrap
                                        margin-left: 5px
                                        font-size: 14px
                                        font-weight: 600
                                  - component: f7-icon
                                    config:
                                      f7: timer
                                      size: 20px
                                      color: blue
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        margin-top: 0px
                                        margin-left: 10px
                                  - component: Label
                                    config:
                                      text: 35min
                                      visible: "=items.Bewaesserung_Rasen_Timer.state === 'ON' ? true : false"
                                      style:
                                        text-overflow: ellipsis
                                        overflow: hidden
                                        white-space: nowrap
                                        margin-left: 5px
                                        font-size: 14px
                                        font-weight: 600
                            - component: f7-row
                              config:
                                class:
                                  - justify-content-flex-start
                                style:
                                  margin-top: 5px
                                  flex-wrap: nowrap
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      material: restore
                                      color: gray
                                      size: 18px
                                      style:
                                        margin-top: 0px
                                        margin-left: 0px
                                  - component: Label
                                    config:
                                      text: 14. April, 18:30
                                      style:
                                        margin-left: 8px
                                        font-size: 12px
                                        color: gray
                                        text-overflow: ellipsis
                                        overflow: hidden
                                        white-space: nowrap
                                  - component: f7-icon
                                    config:
                                      f7: timer
                                      size: 15px
                                      color: gray
                                      style:
                                        margin-top: 2px
                                        margin-left: 10px
                                  - component: Label
                                    config:
                                      text: 20min
                                      style:
                                        margin-left: 3px
                                        font-size: 12px
                                        color: gray
                                        text-overflow: ellipsis
                                        overflow: hidden
                                        white-space: nowrap
          - component: f7-block
            config:
              class:
                - card-prevent-open
                - card-content-padding
              style:
                height: 300px
            slots:
              default:
                - component: oh-list
                  config:
                    class:
                      - padding
                  slots:
                    default:
                      - component: oh-stepper-item
                        config:
                          title: Ausschalt Timer (min)
                          item: Bewaesserung_Rasen_Ausschalt_Timer
                          icon: f7:timer
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: Label
                        config:
                          text: =props.Title?props.Title:"Timer Settings"
                          style:
                            padding: 7px
                            border-bottom: 1px solid grey
                            font-weight: 600
                            color: gray
                            margin-top: 10px
                      - component: oh-toggle-item
                        config:
                          title: Timer
                          icon: f7:alarm
                          color: green
                          item: Bewaesserung_Rasen_Timer
                      - component: oh-input-item
                        config:
                          title: Startzeit
                          type: datepicker
                          sendButton: true
                          item: Bewaesserung_Rasen_Timer_Startzeit
                          outline: false
                          calendarParams:
                            timePicker: true
                            dateFormat:
                              month: short
                              day: numeric
                              hour: numeric
                              minute: numeric
                          style:
                            --f7-input-bg-color: "#ededed"
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Timer_Laufzeit
                          title: Laufzeit (min)
                          icon: f7:timer
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Interval
                          title: Interval (Tage)
                          icon: f7:arrow_2_circlepath
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90
                      - component: Label
                        config:
                          text: =props.Title?props.Title:"Wettersteuerung"
                          style:
                            padding: 7px
                            border-bottom: 1px solid grey
                            font-weight: 600
                            color: gray
                            margin-top: 10px
                      - component: oh-toggle-item
                        config:
                          title: Regenautomatik
                          icon: f7:cloud_rain
                          color: green
                          item: Bewaesserung_Rasen_Regenautomatik
                      - component: oh-stepper-item
                        config:
                          item: Bewaesserung_Rasen_Regenautomatik_Grenzwert
                          title: Grenzwert Regen (mm)
                          icon: f7:chart_bar
                          color: blue
                          raised: true
                          round: true
                          autorepeat: true
                          autorepeatDynamic: false
                          min: 0
                          max: 90

Hope it helps.

4 Likes

i leave it to Stefan to further comment on this widget, but thank you so much @RGroll for sharing your knowledge. I believe this widget with the expandable opportunities gives quite some possiblities to build functionable widgets, eg. for thermostate control and some other stuff and to replace the popup / popover hickups.

Thanks a lot Rainer - much appreciated :slight_smile:
Without your help I would have never find this card-expandable-animate-width - even I read the Card doc already :frowning:

FYI - I had to change the width of the f7-card from 100% to auto.
Otherwise the Widgets was right aligned on the mobile screen.
But now it is perfect :slight_smile:
I will review the code again - I already found a WhnZ_Licht_Main_Dimm item, which doesn’t belong to my watering system :smiley:

Many thanks again!

1 Like

Good to know

Ups, a relict from the quick testing - will update the code in case someone want to use it :smiley:

Happy to help!

once again @stefan13 thanks for sharing this really very useful and nice widget…

3 Likes