Jose Robles
Jose Robles

Reputation: 23

How to use selectizeGroupUI along with DT::datatable in R Shiny

According the examples in the official documentation of selectizeGroup-module, I can do something like this:

library(shiny)
library(shinyWidgets)
library(dplyr)
data("mpg", package = "ggplot2")

ui <- fluidPage(
    fluidRow(
        column(
            width = 10, offset = 1,
            tags$h3("Filter data with selectize group"),
            panel(
                selectizeGroupUI(
                    id = "my-filters",
                    params = list(
                        manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
                        model = list(inputId = "model", title = "Model:"),
                        trans = list(inputId = "trans", title = "Trans:"),
                        class = list(inputId = "class", title = "Class:")
                    )
                ),
                status = "primary"
            ),
            DT::dataTableOutput(outputId = "table")
        )
    )
)

server <- function(input, output, session) {
    
    mpgView2 <- reactive({
        mpg
    })
    
    res_mod <- callModule(
        module = selectizeGroupServer,
        id = "my-filters",
        data = mpgView2,
        vars = c("manufacturer", "model", "trans", "class")
    )
    
    output$table <- DT::renderDataTable({
        req(res_mod())
        res_mod()
    })
}

shinyApp(ui, server)

And the filters work perfect. My requirement also tells me that this table needs to be editable, hide some columns, format round, etc. I'd usually do something like this:

mpgView1 <- reactive({
        DT::datatable(
            mpg,
            filter = "none",
            selection = "none",
            style = "bootstrap",
            extensions = c("Scroller", "FixedColumns"),
            options = list(
                dom = 't',
                scrollY = 500,
                scrollX = 400,
                scroller = TRUE,
                defRender = TRUE,
                autoWidth = TRUE,
                targets = "no-sort",
                bSort = FALSE,
                order = c(),
                fixedColumns = list(leftColumns = 2),
                columnDefs = list(
                    list(
                        visible = FALSE,
                        targets = c(0)
                    ),
                    list(
                        width = "50px",
                        targets = "_all"
                    )
                )
            ),
            editable = list(
                target = 'cell',
                disable = list(columns = c(0,1,2))
            )
        ) %>% 
            DT::formatRound(
                columns = c(3)
            )
        
    })

    output$table <- DT::renderDataTable({ 
     mpgView1()
    })

But now I'm not sure how to "combine" both functionalities. If I do try to put mpgView1() inside res_mod, I get an error:

Warning: Error in as.data.frame.default: cannot coerce class ‘c("datatables", "htmlwidget")’ to a data.frame

I appreciate any help. Thanks.

Upvotes: 2

Views: 1104

Answers (1)

starja
starja

Reputation: 10365

The output of selectizeGroupServer is your filtered data as a reactive, so you can just use this output in the datatable call that is styled to your needs. The requirement that the datatable is editable brings some problems: selectizeGroupServer needs to know the new data. That is possible, however in my solution the table refreshes completely and existing filters are lost. I think you could try to get a bit nicer behaviour with a proxy, but then the combination of the proxy and selectizeGroupServer is a bit trickier.

library(shiny)
library(shinyWidgets)
library(dplyr)
#> 
#> Attache Paket: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
data("mpg", package = "ggplot2")

ui <- fluidPage(
  fluidRow(
    column(
      width = 10, offset = 1,
      tags$h3("Filter data with selectize group"),
      panel(
        selectizeGroupUI(
          id = "my-filters",
          params = list(
            manufacturer = list(inputId = "manufacturer", title = "Manufacturer:"),
            model = list(inputId = "model", title = "Model:"),
            trans = list(inputId = "trans", title = "Trans:"),
            class = list(inputId = "class", title = "Class:")
          )
        ),
        status = "primary"
      ),
      DT::dataTableOutput(outputId = "table")
    )
  )
)

server <- function(input, output, session) {
  
  mpgView2 <- reactiveVal(mpg)
  
  observeEvent(input$table_cell_edit, {
    cell <- input$table_cell_edit
    updated_data <- mpgView2()
    updated_data[cell$row, cell$col] <- cell$value
    mpgView2(updated_data)
  })
  
  res_mod <- callModule(
    module = selectizeGroupServer,
    id = "my-filters",
    data = mpgView2,
    vars = c("manufacturer", "model", "trans", "class")
  )
  
  output$table <- DT::renderDataTable({
    req(res_mod())
    DT::datatable(
      res_mod(),
      filter = "none",
      selection = "none",
      style = "bootstrap",
      extensions = c("Scroller", "FixedColumns"),
      options = list(
        dom = 't',
        scrollY = 500,
        scrollX = 400,
        scroller = TRUE,
        defRender = TRUE,
        autoWidth = TRUE,
        targets = "no-sort",
        bSort = FALSE,
        order = c(),
        fixedColumns = list(leftColumns = 2),
        columnDefs = list(
          list(
            visible = FALSE,
            targets = c(0)
          ),
          list(
            width = "50px",
            targets = "_all"
          )
        )
      ),
      editable = list(
        target = 'cell',
        disable = list(columns = c(0,1,2))
      )
    ) %>% 
      DT::formatRound(
        columns = c(3)
      )
  })
}

shinyApp(ui, server)

Created on 2020-08-26 by the reprex package (v0.3.0)

Upvotes: 1

Related Questions