Puzzle: what is the right FlexContainer / FlexRepeater configuration for a header?

I’m trying to use a Flex Repeater in a header. The flex repeater should be the left-most item in the FlexView and other items in the header should be aligned next to it. This is why I chose the “row” direction for the FlexView

The 1st subview should apperar in top-left, then 2nd subview below and so-on. The items should wrap to a 2nd column if the header is too short. This is why I chose the “column” direction on the FlexRepeater. This is working well.

image

image

Now for the challenge:

The Flex Repeater in the horizontal (row) direction should only use the space it requires to show all of the subviews and not grow beyond that.

As shown above, grow set to “1” on the Flex Container and the Blank Space label gives about half the available horizontal space to each component since they are of equal weight.

Keeping grow=1 on the Label and setting grow=0 on the FlexRepeater also doesn’t work.
image

Below is the JSON for my view if anyone can point me to the properties I need to change:

{
  "custom": {},
  "params": {},
  "props": {
    "defaultSize": {
      "height": 145,
      "width": 402
    }
  },
  "root": {
    "children": [
      {
        "meta": {
          "name": "ListOfButtons"
        },
        "position": {
          "grow": 1
        },
        "props": {
          "alignContent": "flex-start",
          "alignItems": "flex-start",
          "direction": "column",
          "elementPosition": {
            "basis": "auto",
            "grow": 0,
            "shrink": 0
          },
          "instances": [
            {
              "Name": 1
            },
            {
              "Name": 2
            },
            {
              "Name": 3
            }
          ],
          "path": "subview",
          "style": {
            "borderStyle": "solid"
          },
          "useDefaultViewHeight": false,
          "useDefaultViewWidth": false,
          "wrap": "wrap"
        },
        "type": "ia.display.flex-repeater"
      },
      {
        "meta": {
          "name": "Label"
        },
        "position": {
          "grow": 1
        },
        "props": {
          "text": "Blank Space"
        },
        "type": "ia.display.label"
      }
    ],
    "meta": {
      "name": "root"
    },
    "props": {
      "justify": "center"
    },
    "type": "ia.container.flex"
  }
}

you could instead of grow:1 do grow:0.5 or something but there is no way(that i know of) that works to fit content
(or grow 2 on the item on the right)

you could however use float left or something instead of flex

As you point out, the functionality I’m looking for is a “fit” function. My experience has been that grow=0 does this: uses what it needs and nothing more.

@mperkins or @matthew.ayre You guys seem to understand CSS more deeply. Any ideas?

I think you’re misunderstanding what setting grow = 0 does.

Setting the grow = 0 means that when the flex container is stretched, in this case when it’s width is increased, then that component will not grow, it will stay the same size. That size is the basis.

It is better to think in terms of the entire flex container when considering what the grow and shrink settings will actually do.

In this case you have two components in the flex container, the first has a grow property of 0 and the second a grow property of 1. Since 0 + 1 = 1 This means that for every 1 pixel the entire container grows the second component will grow 1 pixel.

See the manual for the a more comprehensive and visual explanation of this:
https://docs.inductiveautomation.com/display/DOC81/Perspective+-+Flex+Container

That answers your question as to why it behaves the way it does, but it doesn’t really solve your problem.

I don’t know what your use case is completely but it looks to me like, in this case you should actually be using a column container, not a flex container.

There really isn’t a “shrink to fit” type of container available. You kind of have to think of all that before hand.

I suppose it wouldn’t be too difficult to change the basis depending upon some criteria but I’m not sure what the end result would really be.

@cmallonee may have a tip on how to achieve what it is you’re looking for, but I suspect that he will need to know more about the actual application.

What if you set grow/shrink to 0 and basis to auto?

With grow/shrink of 0 and basis = auto on the Flex Repeater, the Flex Repeater does use the minimum amount of horizontal space, but just for 1 column of button instances. When the header shrinks, or when there are more buttons than can be accommodated vertically, the Flex Repeater does not expand to the right to show the hidden buttons.

See the following:

image

and

image

Thanks for the feedback.

I hadn’t looked at the column container, but that seems too static and complicated for what I have in mind.

The use-case is:

  • given the header is a fixed height (think of a header along the top of the screen)
  • given the number of buttons (housed within sub-views of the FlexContainer) is dynamic (determined at run-time)
  • given there are other components to the right of the buttons in the header

When buttons are added to the Flex Repeater by a script:

  1. have the order of buttons start in top-left of the Flex Repeater and be shown in a column as many as will fit given the height of the header
  2. if the number of buttons exceeds the height of the header, wrap the buttons to a 2nd column and repeat until all buttons are completely visible (no scroll bars)
  3. push the other elements in the header to the right only as much as is required to display the buttons as the flex container expands (no wasted white-space within the flex repeater container)

Here ya go this works for me (eventho ignition turns it red, which might cause some performance issue in the designer, but should be fine in the client):
you can use css display:grid
try putting these styling into the flex repeater
image

{
  "classes": "",
  "display": "grid",
  "overflow": "auto",
  "grid-auto-flow": "column",
  "grid-template-rows": "repeat(2,1fr)"
}

change the ‘2’ in “grid-template-rows”: “repeat(2,1fr)” to the number of rows you want

I just tried and it also works for me. Great suggestion!

For my particular use-case, having a static number of rows (=2) should work for me, so marking this as a solution.

For other applications, maybe there are other CSS style properties that would not require specifying the number of rows, but automatically expand the container?

Thanks again @victordcq

Glad it worked!

You can do row instead of columns.
But doing both sides seems like a flex box to me xd

but you could probably do something like

display: grid;
grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
grid-auto-flow: dense;

you will have to turn on grow:1 again tho so it is basicly just back to being the flex repeater xd where you came from.