Hide Dash DataTable if there is no data

I have a complicated dashboard with lots of charts and tables not all of which should be displayed in all cases. For example, say I have 3 schools, one is K-8 (elementary & middle school), one is 9-12 (high school), and one is K-12 (elementary/middle/high school).

If the first school is selected, I only display the charts/tables that are relevant for K-8.
If the second school is selected, I only display the charts/tables that are relevant for a HS.
If the third school is selected, I display all the charts/tables.

If a chart/table is relevant, but has no data, I display an ‘empty’ datatable or fig. But if a chart/table is not relevant, I don’t display it at all.

What I have been doing to hide tables/figs completely is using <div> ids and the ‘style’ property of the component. e.g.,

Output('k8--table-container', 'style')
Output('hs-table-container', 'style')

and then returning the container variable as either:

hs_table_container = {'display': 'block'}
hs_table_container = {'display': 'none'}

This works and is fine. However, I have now run into a situation where there are 14 separate table/chart combinations where I do not want to display a table/chart at all if there is no data. I started to simply add an extra container div for each chart/table, but it seems unnecessarily wordy (each chart table gets a ‘style’ prop and an extra <div> id) which results in 42! separate Outputs. Is there an easier way to do this? Like creating a 0width/0height empty table and chart that I can return instead?

Hello @etonblue,

You could probably achieve this with some css magic:

.dash-table-container:not(:has(td)) {
    display: none;
}

My css game is pretty weak. How would this be triggered?

It is automatically applied to any table without a cell (headers not included).

Then any table matching that will not show at all.

Ah, I like this. Unfortunately my layout is styled with a bunch of nested container divs. So while this works to hide the table, a blank outer container is still displayed. Don’t suppose there is a css trick to hide these container divs if the table itself is hidden?

I dont know what your overall container class is, but more than likely, yes.

.container:has(.dash-table-container:not(:has(td))) {
    display: none;
}

This may work? :slight_smile:

I have a ‘pretty_container’ nested inside of a ‘bare_container’:

.pretty_container {
  border-radius: 5px;
  background-color: #ffffff;
  margin: 10px;
  padding: 15px;
  position: relative;
  box-shadow: 2px 2px 2px lightgrey;
}

.bare_container {
  margin: 0 0 0 0;
  padding: 0 0 0 0;
  justify-content: center;
  text-align: center;
  align-items: center;
  display: flex;
}

Used like this (this is the actual code I am using to test):

html.Div(
    [
        html.Div(
            [
                dash_table.DataTable(id="hidden-table",
                    columns=[
                        {'id': "foo", 'name': "bar"},
                    ],
                ),
            ],
            className='pretty_container six columns',
        ),
    ],
    className='bare_container twelve columns',
),

the six and twelve columns are:

.columns {
  width: 100%;
  float: left;
  box-sizing: border-box;
}

.six.columns {
    width: 49.75%;
}

.twelve.columns {
    width: 100%;
    margin-left: 0;
}

The first css code you gave me worked, but neither of these do anything:

.pretty_container:has(.dash-table-container:not(:has(td))) {
  display: none;
}

.bare_container:has(.dash-table-container:not(:has(td))) {
  display: none;
}

Try this:

.pretty_container:not(:has(div.dash-table-container td)) {
  display: none;
}
1 Like

That did the trick! Thanks!

I want to run some more tests, but this could potentially save me many lines of code. From a testing perspective, do you know if this solution as robust as the one I am using currently? Across browsers and such?

I think most modern browsers support this type of css selector navigation.

Oops. May have spoken too soon. The code will hide any pretty_container that doesn’t have a table with a cell. Unfortunately, this means it hides any containers that have any other type of component, e.g., a fig, dropdown, buttons, etc.

As I see it, I could either: 1) create specific container classes for tables and tie the ‘has’ condition to those classes only; or 2) chain selectors together to ensure all possibly display conditions are accounted for. For example:

.pretty_container:not(:has(div.dash-table-container td,div.js-plotly-plot)) {
  display: none;
}

Only hides containers that don’t have either: a table with a cell or a js-plotly-plot object (not sure if this is the correct parameter to use). So this will display figs.

But I also have dropdowns inside containers. So I also need:

.pretty_container:not(:has(div.dash-table-container td,div.js-plotly-plot,div.dash-dropdown)) {
  display: none;
}

This appears to work for all of my use cases. However, it also seems like it is less clear than my existing solution in terms of code readability. It also seems more prone to breaking or behaving in unintended ways.

Thoughts?