Data table (template)

This is not strictly a widget that you can readily use, but a template of sorts which you can import and modify as needed. It offers a generic data table with a few clues to help you figure out how you can suit it to your needs.
It will help you make a Framework7 data table that is responsive, that is, it will automatically convert to a list on narrower screens.
I have not seen it done before and it’s maybe something many could use. It also shows how you can use the latest features, like just using HTML tags as the component or the @ prefixes for item states.

Screenshot from 2023-05-09 22-39-57

The Widget YAML

uid: data_table
tags: []
props:
  parameters: []
  parameterGroups: []
timestamp: May 9, 2023, 8:28:49 PM
component: div
config:
  class:
    - card
    - data-table
    - data-table-collapsible
    - data-table-init
slots:
  default:
    - component: div
      config:
        class:
          - card-header
      slots:
        default:
          - component: div
            config:
              class:
                - data-table-title
              content: Nutrition
    - component: table
      config: {}
      slots:
        default:
          - component: oh-repeater
            config: {}
          - component: thead
            slots:
              default:
                - component: tr
                  slots:
                    default:
                      - component: th
                        config:
                          class:
                            - label-cell
                          content: Dessert (100g serving)
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Calories
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Fat (g)
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Carbs
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Protein (g)
          - component: tbody
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: food
                    fragment: true
                    in:
                      - calories: 159
                        carbs: =@'ElectricityMeter_Power'
                        fat: "6.0"
                        name: Frozen Yoghurt
                        protein: "4.0"
                      - calories: 237
                        carbs: 37
                        fat: "9.0"
                        name: Ice Cream Sandwich
                        protein: "4.4"
                      - calories: 262
                        carbs: 24
                        fat: "16.0"
                        name: Eclair
                        protein: "6.0"
                      - calories: 305
                        carbs: 67
                        fat: "3.7"
                        name: Cupcake
                        protein: "4.3"
                  slots:
                    default:
                      - component: tr
                        slots:
                          default:
                            - component: td
                              config:
                                class:
                                  - label-cell
                                content: =loop.food.name
                                data-collapsible-title: Dessert
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.calories
                                data-collapsible-title: Calories
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                data-collapsible-title: Fat (g)
                              slots:
                                default:
                                  - component: span
                                    config:
                                      visible: =loop.food.fat < 10
                                      content: =loop.food.fat
                                  - component: f7-chip
                                    config:
                                      visible: =loop.food.fat >= 10
                                      color: red
                                      text: =loop.food.fat
                                      icon-f7: exclamationmark_triangle_fill
                                      style:
                                        font-size: var(--f7-table-body-font-size)
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.carbs
                                data-collapsible-title: Carbs
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.protein
                                data-collapsible-title: Protein (g)

How to change

This is offered as a card but if you want to integrate it to another widget you can remove the card class from the root component, as well as the first div component under the default slot to remove the “Nutrition” header:

Screenshot from 2023-05-09 23-03-17

The columns are defined in two places, first under the thead component (for the headers):

          - component: thead
            slots:
              default:
                - component: tr
                  slots:
                    default:
                      - component: th
                        config:
                          class:
                            - label-cell
                          content: Dessert (100g serving)
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Calories
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Fat (g)
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Carbs
                      - component: th
                        config:
                          class:
                            - numeric-cell
                          content: Protein (g)

The label-cell and numeric-cell classes determine the alignment. Note that you can also use classes like xsmall-only, small-only, medium-only, large-only, xlarge-only to display columns only when the screen is large enough.

To build the table’s body we use a oh-repeater directly under the tbody HTML tag:

          - component: tbody
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: food
                    fragment: true
                    in:
                      - calories: 159
                        carbs: =@'ElectricityMeter_Power'
                        fat: "6.0"
                        name: Frozen Yoghurt
                        protein: "4.0"
                      - calories: 237
                        carbs: 37
                        fat: "9.0"
                        name: Ice Cream Sandwich
                        protein: "4.4"
                      - calories: 262
                        carbs: 24
                        fat: "16.0"
                        name: Eclair
                        protein: "6.0"
                      - calories: 305
                        carbs: 67
                        fat: "3.7"
                        name: Cupcake
                        protein: "4.3"

In this case we feed it an array of objects with several properties (the in: parameter of the oh-repeater). Note how it can include expressions (the “carbs” property of the Frozen Yoghurt was changed to an expression which uses the state of the ElectricityMeter_Power item by employing the @ operator).

In the default slot of the oh-repeater we define the repeated rows and columns:

                  slots:
                    default:
                      - component: tr
                        slots:
                          default:
                            - component: td
                              config:
                                class:
                                  - label-cell
                                content: =loop.food.name
                                data-collapsible-title: Dessert
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.calories
                                data-collapsible-title: Calories
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                data-collapsible-title: Fat (g)
                              slots:
                                default:
                                  - component: span
                                    config:
                                      visible: =loop.food.fat < 10
                                      content: =loop.food.fat
                                  - component: f7-chip
                                    config:
                                      visible: =loop.food.fat >= 10
                                      color: red
                                      text: =loop.food.fat
                                      icon-f7: exclamationmark_triangle_fill
                                      style:
                                        font-size: var(--f7-table-body-font-size)
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.carbs
                                data-collapsible-title: Carbs
                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                content: =loop.food.protein
                                data-collapsible-title: Protein (g)

Note the two options used here. Most columns just define a td with a content config property, and the appropriate classes and other properties (data-collapsible-title is used when the table is collapsed to a label/value list as shown above, the value in that property will be the label).

For the Fat (g) column, however, we have this:

                            - component: td
                              config:
                                class:
                                  - numeric-cell
                                data-collapsible-title: Fat (g)
                              slots:
                                default:
                                  - component: span
                                    config:
                                      visible: =loop.food.fat < 10
                                      content: =loop.food.fat
                                  - component: f7-chip
                                    config:
                                      visible: =loop.food.fat >= 10
                                      color: red
                                      text: =loop.food.fat
                                      icon-f7: exclamationmark_triangle_fill
                                      style:
                                        font-size: var(--f7-table-body-font-size)

We have defined a default slot for the td (table cell) with 2 components that will be alternatively displayed if the fat property of the current item in the array that acts as a source to the oh-repeater is below or above 10 (using the visible property).

The two alternatives are a span component (which is maybe the simplest HTML tag and will just insert the text into the cell), or a f7-chip component when the value is higher or equal than 10, which will render with a rounded red backdrop and associated icon. We also redefine the font size with the CSS variable used for table cells (see https://www.openhab.org/docs/ui/building-pages.html#css-variables)

Changelog

Version 0.1

  • initial release
4 Likes