1
votes

My Shiny App has a paging system, that allows to go back and forth. Below is a miniversion of my entire app. I would like to resize the first column of my datatable that includes checkboxes and make it at least half of the size as it is at this point, to allow for more space for the actual text in the second column. How do you correctly adjust the first column?

I tried it within the renderdatatable command with: columnDefs = list(list(targets= 0, width= '30px'). Did not work.

I also added autoWidth= TRUE within options=list() as suggested here and here, however, that makes the entire table smaller. Below you can see how I included these within the code.

output$table_p2 <- DT::renderDataTable(
      checkboxtable2,
      server = FALSE, escape = FALSE, selection = 'none',
      rownames = FALSE,
      options = list(
        dom = 't', paging = FALSE, ordering = FALSE,autoWidth = TRUE,
        columnDefs = list(list(targets= 0, width= '30%')),
        preDrawCallback = JS('function() { 
        Shiny.unbindAll(this.api().table().node()); }'),
        drawCallback = JS('function() { 
        Shiny.bindAll(this.api().table().node()); } '))
    )

I also tried to use the new syntax aoColumnDefs() as suggested here. Which I also could not make to work. How can I explicitly decrease the width of the first column?

ShinyApp

## miniversion of survey
if(!require(shiny))install.packages("shiny");require(shiny)
if(!require(shinyjs)) install.packages("shinyjs"); require(shiny)
if(!require(htmlwidgets)) install.packages("htmlwidgets"); require(htmlwidgets)
if(!require(shinyWidgets)) install.packages("shinyWidgets"); require(shinyWidgets)
if(!require(DT)) install.packages("DT"); require(DT)


answer_options = c("riding", "climbing", "travelling", "binge watching series", "swimming", "reading")

# https://stackguides.com/questions/37875078/shiny-checkbox-in-table-in-shiny/37875435#37875435
shinyInput <- function(FUN, ids, ...) {
  inputs <- NULL
  inputs <- sapply(ids, function(x) {
    inputs[x] <- as.character(FUN(inputId = x, label = NULL, ...))
  })
  inputs
}

# 
shinyApp(
  ui = fluidPage( ####
    useShinyjs(),# For Shinyjs functions
    tags$script("
                Shiny.addCustomMessageHandler('resetValue', function(variableName) {
                Shiny.onInputChange(variableName, null);
                });
                "),

    tags$style('{background-color: #256986;}'),

    div(class="content",
        # progressbar showing the progress of the survey, currently moves ahead per page in steps of 
        # 12.5 (excluding intro and thank you page)

        progressBar(id= "pbar", value= 0, size= "xs"),

        # main utput/ modified userinterface for each page
        uiOutput("MainAction")
        )
    ),



  server =function(input, output, session) { ####
    output$MainAction <- renderUI({
      PageLayouts()
    })

    CurrentPage <- reactiveValues(page= "page1",
                                  selected= 0)
    PageLayouts<- reactive({


      if(CurrentPage$page == "page1"){
        return(
          list(
            textInput(inputId = "username", label= "Please enter your username"),

            # button displayed to continue
            div(class= "next button",actionButton(inputId = "p1_next", #input ID refers to following page
                                                  label= "Continue"))
          ))
      }


      if(CurrentPage$page == "page2"){
        checkboxtable2 <- data.frame(
          "answer options" = shinyInput(checkboxInput, answer_options),
          "What are your hobbies?" = answer_options,
          check.names = FALSE
        )

        output$table_p2 <- DT::renderDataTable(
          checkboxtable2,
          server = FALSE, escape = FALSE, selection = 'none',
          rownames = FALSE,
          options = list(
            dom = 't', paging = FALSE, ordering = FALSE,
            columnDefs = list(list(targets= 0, width= '30px')),
            preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
            drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } '))
        )

        return(
          list(
            # create datatable with checkboxes
            p("What are your hobbies?"),
            # create datatable with checkboxes
            # surpresses header without removing checkboxes
            tags$head(tags$style(type = "text/css", "#table_p2 th {display:none;}")),
            DT::dataTableOutput('table_p2'),

            updateProgressBar(session= session, id= "pbar", value = 12.5),
            tags$style(".progress-bar {background-color: #25c484;}")
          ))

      }
    })

      observeEvent(input$p1_next, {CurrentPage$page <- "page2"})
      })

Comment in case you are wondering about the construction of the datatable: The procedure I follow to create these tables is to create dataframes first out of two vectors (one of which includes the checkboxes), transform these into DataTables with renderDataTable, followed by returning the table without the header by overwriting its CSS in a list. I had to follow this procedure, as all other methods to return a checkbox table without a header row, resulted in a data table without checkboxes. Therefore, the code had to be split as I could not create vectors with checkboxes in a list.

1

1 Answers

0
votes

DataTables are not very nice, when it comes to column widths. It sais here that widths will never be taken literally from the given definition, but always adapted to the table size and what not. Thats why your efforts were in vain.

But you can still shape things to your need. At first, using checkboxInput creates a container around the checkbox that has a default width of 300 pixels, which are the main reason for the column to be so big. You could in a first step unset this width to see what "natural" size the column would have.

If you want to reduce the size even more, a css rule for the column's width is working fine. For that and the above part, we equip the first column cells with a specific class name.

Weave

columnDefs = list(list(targets = 0, className = "small" ))

into your DataTable definition and then add

td.small .shiny-input-container{width:auto;}

to your css to unset the predefined width in this column.

Further minifications can be achieved by the css rule

td.small{width:30px;}