2

I'm trying to create an interactive calculator using R Markdown and Shiny. The calculator will sum car prices, from an imported table, based on whether check boxes are triggered. I've created a basic shell for the calculator, but I'm stuck not knowing how to reference the check boxes.

I want my checkboxes to be in line with my table, and wasn't able to use checkBoxGroupInput to do so. I did, however, find this recent SO thread which suggests I can use cbind to combine (what looks to be) an HTML vector of checkboxes with a datatable:

---
output: html_document
runtime: shiny
---

### Select car(s)
```{r, echo=FALSE}

## import car data
data <- head(mtcars[1:6])
data$id <- seq(1:nrow(data))

## generate random car prices
set.seed(1)
data$price <- round(runif(nrow(data),5000,15000),0)

## create table w/ checkboxes
output$mytable = renderDataTable({
  addCheckboxButtons <- paste0('<input id="table1" type="checkbox" name="row', data$id, '" value="op', data$id, '">',"")
  #Display table with checkbox buttons
  z <- cbind(Pick=addCheckboxButtons, data)
  z
})

## display table
dataTableOutput({"mytable"})
```

This code above works fine and produces the table I want. I get stuck, however, as I'm unsure how to now reference my checkbox vector. I know I need to use a reactive statement to do my summation, but I'm not exactly sure how to do reference the check boxes to do so. I imagine the last piece of code will look something like:

### Total bill
```{r, echo=FALSE}
my_sum <- reactive({z$price[z$Pick=="TRUE"]})
renderText(my_sum)
```

The code blows up as the data$Pick part doesn't work. The error I get is:

Error: argument 1 (type 'closure') cannot be handled by 'cat'

(As I understand it, renderText is passing the first argument to cat, which does not know what to do with the function.)

Can someone please help me reference the checkboxes I've created?

Community
  • 1
  • 1
Hip Hop Physician
  • 252
  • 1
  • 3
  • 12

1 Answers1

3

With a few changes you can do it. Introduce a reactive variable to reference your table values. Add a class to your checkboxes and remove the id.

## make reactive variable
myZ <- reactive({
    addCheckboxButtons <- paste0('<input class = "mycheckbox" type="checkbox" name="row', data$id, '" value="op', data$id, '">',"")
  #Display table with checkbox buttons
  z <- cbind(Pick=addCheckboxButtons, data)
  z
})

Add a callback for your table. When a row is clicked the checkboxes status is checked and returned as a string.

## create table w/ checkboxes
output$mytable = renderDataTable({
  myZ()
},
    callback = "function(table) {
    table.on('click.dt', 'tr', function() {
    Shiny.onInputChange('rows',$('.mycheckbox').map(function(){return this.checked*1;}).get().join(\",\"))
    });
}")

## display table
dataTableOutput({"mytable"})
```

Manipulate the returned string of 0,1 's indicating whether boxes are checked and use it to select from table.

### Total bill
```{r, echo=FALSE}
my_sum <- reactive({
  myZ()$price[myZ()$Pick=="TRUE"]
  })
output$mytext <- renderText({idx <-strsplit(input$rows, ",")[[1]] == "1"
                             sum(myZ()$price[idx])
                             }
                            )
textOutput("mytext")
```
jdharrison
  • 30,085
  • 4
  • 77
  • 89
  • This is **fantastic**, thank you very much! For anyone following along, make sure to first import the data and append the prices before using the rest of jdharrison's code. Also, the summation value will be null and will cause an error until any checkbox is selected, but this will be an easy fix with some error handling logic. – Hip Hop Physician Dec 16 '14 at 15:15
  • 1
    Happy to help. You could return the sum directly from the `Shiny.onInputChange` but it maybe useful to have the vector of checkboxes for other calculations. – jdharrison Dec 16 '14 at 15:23