Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically Hiding Empty Columns #370

Open
mrworthington opened this issue Apr 11, 2024 · 1 comment
Open

Automatically Hiding Empty Columns #370

mrworthington opened this issue Apr 11, 2024 · 1 comment

Comments

@mrworthington
Copy link

Hi Greg,

I'm wondering if it's possible to automatically hide columns that are empty within the Reactable Javascript API you've got built out. Your package is pretty amazing when paired with observable and I'm loving it. This is a fairly niche issue that I can't seem to resolve, but it looks like there's some discussion about this within the underlying react-table library on stackoverflow. I just can't figure out if it can work within the API functions you've built out for {reactable}.

Essentially the goal is to take a tibble like the one below, pass it to reactable, and use the Javascript API to automatically hide empty columns instead of having to name all of them. The functionality I'm asking about is essentially like janitor's remove_empty(which="cols) but within the browser. I have a tibble like the one below with dozens and dozens of columns and thousands of rows with categories. Depending on the category, you'll have empty columns like the table below in column E. Instead of explicitly naming them like I've done below with Reactable.setHiddenColumns() (which would be impossible in my use case), I'm wondering if it's possible to dynamically hide them with the Javascript API.

Thanks in advance, Greg!

## Demo Doc
---
title: "Demo Doc"
format: html
---

```{r}
#| message: false
#| echo: false
#| output: false
library(tidyverse)
library(htmltools)
library(reactable)

data_tbl <- tibble(
  a = c(1,2,3),
  b = c(NA,4,NA),
  c = c(5,NA,6),
  d = c(NA, NA, NA),
  e = c(7,8,9)
)

ojs_define(data_ojs = data_tbl)
```

```{ojs}
//| output: false
//| eval: true

Reactable.setHiddenColumns('tbl', ['d'])
```

```{r}
reactable(
  data_tbl,
  elementId = "tbl"
)
```
@glin
Copy link
Owner

glin commented Apr 16, 2024

The table data is available in the JavaScript API via Reactable.getState(), so you could potentially check that for empty columns and call setHiddenColumns() on the result. Or if it has to be done dynamically, like if a filtering causes a column to go empty, then you can watch for table data changes via Reactable.onStateChange() instead.

Here's a quick and dirty example adapted from above. One gotcha is that you also have to check that the new hidden columns haven't changed from the existing ones, or onStateChange() will get into an infinite loop of making and reacting to changes.

## Demo Doc
---
title: "Demo Doc"
format: html
---

```{r}
#| message: false
#| echo: false
#| output: false
library(tidyverse)
library(htmltools)
library(reactable)

data_tbl <- tibble(
  a = c(1,2,3),
  b = c(NA,4,NA),
  c = c(5,NA,6),
  d = c(NA, NA, NA),
  e = c(7,8,9)
)

ojs_define(data_ojs = data_tbl)
```

```{ojs}
//| output: false
//| eval: true

Reactable.onStateChange('tbl', state => {
  const { sortedData, hiddenColumns } = state
  const emptyColumns = {}
  for (let row of sortedData) {
    for (let [column, value] of Object.entries(row)) {
      if (!emptyColumns.hasOwnProperty(column)) {
        emptyColumns[column] = true
      }
      if (value != null) {
        emptyColumns[column] = false
      }
    }
  }

  const emptyColIds = []
  for (let [column, isEmpty] of Object.entries(emptyColumns)) {
    if (isEmpty) {
      emptyColIds.push(column)
    }
  }

  const hasChanged = !emptyColIds.every(id => hiddenColumns.includes(id)) || !hiddenColumns.every(id => emptyColIds.includes(id))
  if (hasChanged) {
    Reactable.setHiddenColumns('tbl', emptyColIds)
  }
})
```

```{r}
reactable(
  data_tbl,
  searchable = TRUE,
  elementId = "tbl"
)
```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants