How to hide oh-cell when using visibleTo in oh-masonry or oh-grid-cells

I’m trying to improve the homepage layout by hiding things family members are not interested in. For example the music and light controls in my office room are my priority (something I want right at the top) but for others it only clutters up the screen. Using visibleTo would work perfectly fine for this scenario if I were able to hide the cell together with the hidden widget. Unfortunately, the cell gets rendered empty and uses up the space.

Here is an example of an oh-masonry with two widgets, each visible to another user:

component: oh-masonry
config:
  cols:
    "768": 1
    "1023": 3
    "1280": 1
    default: 3
slots:
  default:
    - component: oh-cell
      config:
        action: navigate
        actionPage: page:page_4dc338c9ad
        header: Schlafen
        icon: f7:bed_double
        title: Julia
        visibleTo:
          - role:administrator
          - user:julia
    - component: oh-cell
      config:
        action: navigate
        actionPage: page:page_53bb7591e7
        header: Schlafen
        icon: f7:bed_double
        title: Marcus
        visibleTo:
          - role:administrator
          - user:marcus

Now, if I am logged in as user marcus, it looks like this:

As expected, the widget is not shown but it’s cell still uses up the space.

Creating an oh-grid-cells or masonry for every user and hiding the whole block is working but this would make no sense as I would have to replicate nearly all widgets for every user.

So how do I hide cells without content?

not sure if that solves the problem but worth a try:

component: =(user.name == "marcus")?"oh-cell":""

Good idea but this syntax does not seem to be supported : YAMLSemanticError: Nested mappings are not allowed in compact mappings

you have to delete whitespaces around :

The syntax seems good without the whitespace but component: “” just renders an empty cell like with oh-cell. Maybe I can use this to modify the style somehow but so far I found nothing that prevents the cell from getting rendered, i.e.:

config
  style:
    display: =(user.name=="marcus")?"relative":"none"
    width: =(user.name=="marcus")?"auto":"0px"

still renders the cell.

Looks like the width does not come form the cell itself but from the elements containing the cell and I guess this is where we have little control over.

maybe creating a “dummy” widget of 0px of size (width)?
However, I am not familiar with oh-masonry.
Are there any more details available if you inspect the page? Is there an oh-cell rendered or an empty parent-container?

Seems it requires some additional code support to render the outer container only if there is a visible component inside. It works with oh-grid-col when using visibleTo inside the column configuration:

        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  visibleTo:
                    - role:administrator
                    - user:julia
                slots:
                  default:
                    - component: oh-cell
                      config:
                        action: navigate
                        actionPage: page:page_4dc338c9ad
                        header: Schlafen
                        icon: f7:bed_double
                        title: Julia
                        visibleTo:
                          - role:administrator
                          - user:julia
              - component: oh-grid-col
                config:
                  visibleTo:
                    - role:administrator
                    - user:marcus
                slots:
                  default:
                    - component: oh-cell
                      config:
                        action: navigate
                        actionPage: page:page_53bb7591e7
                        header: Schlafen
                        icon: f7:bed_double
                        title: Marcus
                        visibleTo:
                          - role:administrator
                          - user:marcus

However, this type of static layout is not particularly well suited for this use case.

Most components, including the oh-grid-col accept a visible parameter which takes a boolean value. If the visible parameter is false, that component isn’t even rendered. So in this case you want to add:

visible: =(user.name=="marcus")

to the oh-grid-col to completely remove that column from the row.

This seems to do the same as the visibleTo property. It hides the cell but the outer element is still present and consumes the width:

This is how it looks if visible is false or visibleTo does not match:

oh3emptycell

Edit: Sorry, I see now that you are trying to use masonry instead of the row and col grids.

The default oh-masonry will always have the number of columns that matches the number of child components even if one of those components is not visible. You can fix this with a property of the oh-masonry

  - component: oh-masonry
    config:
      flavor: css-grid

With that property an invisible component should not contribute a column to the masonry. Without seeing your whole page code, or more information about your particular use-case, I cannot say if there are any negative side-effects of using the flavor property.

This seems to work. Thanks a lot! Interestingly, only in Chrome does this display each widget on its own line. FF looks fine. I’ll test it some more with the app and a few more widgets.

These are some of the down-stream effects I mentioned. One of the impacts of changing the flavor property is that your masonry is then rendered with display: block which is just less responsive then something like display: flex. Now you can fix that too by adding a stylesheet parameter to the page config. Something like this:

config:
  stylesheet: >
    .oh-masonry {
      display: flex;
    }

But there’s a chance that also impacts some of the widgets in the masonry depending on how they are designed.

Ultimately, I think this issue is an XY problem. You don’t need to resort to component or column hiding shenanigans if you just make the component itself responsive. You only need a single cell; you just have to modify its contents based on the user which you can do in 3.4:

    - component: oh-cell
      config:
        action: navigate
        actionPage: =(user.name=='marcus')?('page:page_53bb7591e7'):('page:page_4dc338c9ad')
        header: Schlafen
        icon: f7:bed_double
        title: =(user.name=='marcus')?('Marcus'):('Julia')

That’s a good idea but it won’t work in all cases. My goal is a clean home screen layout with things not relevant for a user removed. That’s why some widgets won’t be shown and this is where the whole issue begins with the masonry.

Maybe I can fix this using the stylesheet idea. It only needs an CSS selector which sets display:none on cells without children.

I don’t believe this will work. There shouldn’t really be any functional difference between setting a component’s visible property and setting display: none. They both wind up just not rendering that particular element; it’s only a matter of whether that element is not rendered while compiling the vue or parsing the html. But, your issue isn’t with the element itself, it’s with the oh-masonry.

When the oh-masonry uses the default settings it’s using the vue masonry library and you can see that this winds up wrapping each oh-masonry-item in an additional div container:

<div style="display: flex; margin-left: 0px;">
  <div class="" style="box-sizing: border-box; background-clip: padding-box; width: 25%; border: 0px solid transparent;">
    <div class="oh-masonry-item">
  <div class="" style="box-sizing: border-box; background-clip: padding-box; width: 25%; border: 0px solid transparent;">
    <div class="oh-masonry-item">

Those extra containers are the masonry columns (which means they are fixed-width based on the number of columns in the masonry) and they don’t go away even if there’s nothing rendered in the oh-masonry-item container. As far as the vue masonry library is concerned, that’s a feature not a bug.

When you set the flavor: css-grid then the oh-masonry just uses a regular div for its top-level element (with a different set of stylings) and those extra column containers are not created:

<div class="oh-masonry">
  <div class="oh-masonry-item" style="z-index: 100;">
  <div class="oh-masonry-item" style="z-index: 99;">

This is why, when you use the css-grid “flavor” of masonry you get the child elements stacked instead of inline, the top-level container doesn’t have display: flex set and you have to do it yourself using the page stylesheet. I’ve never looked comprehensively, so I don’t know what other style differences there are between the top-level containers in these two scenarios which is why I said there might be additional downstream effects of using the css-grid. There also might not.

If the combination of flavor: css-grid and setting the flex with the stylesheet works, then just go with that. That combination should probably work both with the visible and visisbleTo settings. While there may be other solutions, you’re not going to find a more direct solution to hiding elements while using the oh-masonry.