rr-markdownflexdashboardreactablecrosstalk

Show empty table before filtering with crosstalk


I would like to filter a reactable with crosstalk. Let's say I have the following Rmd-file:

---
title: "blabla"
output:
   flexdashboard::flex_dashboard:
   orientation: rows
   social: menu
   source_code: embed
   theme: cerulean
---

```{r}
library(crosstalk)
library(tidyverse)
```

```{r Make dataset}
df1 <- structure(list(owner = structure(c(1L, 2L, 2L, 2L, 2L), .Label = c("John", "Mark"), 
class = "factor"), hp = c(250, 120, 250, 100, 110), car = structure(c(2L, 2L, 2L, 1L, 1L), .Label = c("benz", "bmw"), class = "factor"), id = structure(1:5, .Label = c("car1", "car2", "car3", "car4", "car5"), class = "factor")), .Names = c("owner", "hp", "car", "id"), row.names = c(NA, -5L), class = "data.frame")

df2 <- structure(list(car = structure(c(1L, 2L, 1L, 2L), .Label = c("benz", 
"bmw"), class = "factor"), owner = structure(c(1L, 1L, 2L, 2L
), .Label = c("John", "Mark"), class = "factor"), freq = c(0L, 
1L, 2L, 2L)), .Names = c("car", "owner", "freq"), row.names = c(NA, 
-4L), class = "data.frame")
```

#

##

### Filters

```{r}
library(crosstalk)
# Notice the 'group = ' argument - this does the trick!
shared_df1 <- SharedData$new(df1, ~owner, group = "Choose owner")
shared_df2 <- SharedData$new(df2, ~owner, group = "Choose owner")

filter_select("owner", "Car owner:", shared_df1, ~owner)
```


##

### Dataframe 1

```{r}
reactable::reactable(shared_df1)
```

### Dataframe 2

```{r}
reactable::reactable(shared_df2)
```

Now before the user enters a car owner the table shows the rows for all car owners. I would like to achieve that the table is empty, and only if a car owner is entered, the table should show the information for this car owner. Is this possible to achieve? I am looking for a solution without Shiny.

The example above is deduced from: Filter two tables with crosstalk.


Solution

  • I don't know how to do it with crosstalk and tried to search for their docs and maybe this is not supported. BUT, we can do it with some javascripts.

    function toggleDF(hasItem, selector) {
        if(!hasItem) {
            $(selector).hide();
        } else {
            $(selector).show();
        }
    }
    $(function(){
        // hide on start
        toggleDF(false, '#dataframe-1 .ReactTable .rt-tbody');
        toggleDF(false, '#dataframe-2 .ReactTable .rt-tbody');
        $('#owner').on("change", function(){
            var hasItem = $(this).find('.selectize-input').hasClass('has-items');
            // hide/show based on selection
            toggleDF(hasItem, '#dataframe-1 .ReactTable .rt-tbody');
            toggleDF(hasItem, '#dataframe-2 .ReactTable .rt-tbody');
        });
    });
    
    1. A function toggleDF to show and hide the table body.
    2. Some expressions to trigger the function based on whether you have selections in the owner dropdown.
    3. In the expression, it requires you to put the reactable under certain title so we can find the ID, eg ### Dataframe 2's ID is dataframe-2, lower case of all letters and dash replace spaces (how Rmarkdown translate titles to IDs).

    Full code

    ---
    title: "blabla"
    output:
       flexdashboard::flex_dashboard:
       orientation: rows
       social: menu
       source_code: embed
       theme: cerulean
    ---
    
    ```{r}
    library(crosstalk)
    library(tidyverse)
    ```
    
    ```{r Make dataset}
    df1 <- structure(list(owner = structure(c(1L, 2L, 2L, 2L, 2L), .Label = c("John", "Mark"), 
    class = "factor"), hp = c(250, 120, 250, 100, 110), car = structure(c(2L, 2L, 2L, 1L, 1L), .Label = c("benz", "bmw"), class = "factor"), id = structure(1:5, .Label = c("car1", "car2", "car3", "car4", "car5"), class = "factor")), .Names = c("owner", "hp", "car", "id"), row.names = c(NA, -5L), class = "data.frame")
    
    df2 <- structure(list(car = structure(c(1L, 2L, 1L, 2L), .Label = c("benz", 
    "bmw"), class = "factor"), owner = structure(c(1L, 1L, 2L, 2L
    ), .Label = c("John", "Mark"), class = "factor"), freq = c(0L, 
    1L, 2L, 2L)), .Names = c("car", "owner", "freq"), row.names = c(NA, 
    -4L), class = "data.frame")
    ```
    
    #
    
    ##
    
    ### Filters
    
    ```{r}
    library(crosstalk)
    # Notice the 'group = ' argument - this does the trick!
    shared_df1 <- SharedData$new(df1, ~owner, group = "Choose owner")
    shared_df2 <- SharedData$new(df2, ~owner, group = "Choose owner")
    
    filter_select("owner", "Car owner:", shared_df1, ~owner)
    ```
    
    
    ##
    
    ### Dataframe 1
    
    ```{r}
    reactable::reactable(shared_df1)
    ```
    
    ### Dataframe 2
    
    ```{r}
    reactable::reactable(shared_df2)
    ```
    
    <script>
    function toggleDF(hasItem, selector) {
        if(!hasItem) {
            $(selector).hide();
        } else {
            $(selector).show();
        }
    }
    $(function(){
        // hide on start
        toggleDF(false, '#dataframe-1 .ReactTable .rt-tbody');
        toggleDF(false, '#dataframe-2 .ReactTable .rt-tbody');
        $('#owner').on("change", function(){
            var hasItem = $(this).find('.selectize-input').hasClass('has-items');
            // hide/show based on selection
            toggleDF(hasItem, '#dataframe-1 .ReactTable .rt-tbody');
            toggleDF(hasItem, '#dataframe-2 .ReactTable .rt-tbody');
        });
    });
    </script>
    

    screenshot