R Shiny, How to Make Datatable React to Checkboxes in Datatable

R Shiny, how to make datatable react to checkboxes in datatable

Yes, your example code almost works. The only thing not right is that the value of df$cb needs to be changed, too.

For example, let's say you clicked the second row and input$cb_2 gets changed. shiny would record that input$cb_2 got changed to FALSE. Since the value of df$cb[[2]] was still checkbox(..., value = TRUE), when the table gets re-drawed, a checked checkbox would be displayed and R thought that input$cb_2 got changed again and so your data would be altered correspondly.

Checked the example code if there's anything uncleared.

The worked example code

library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DT::dataTableOutput('x1'),
verbatimTextOutput('x2')
),

server = function(input, output, session) {
# create a character vector of shiny inputs
shinyInput = function(FUN, len, id, value, ...) {
if (length(value) == 1) value <- rep(value, len)
inputs = character(len)
for (i in seq_len(len)) {
inputs[i] = as.character(FUN(paste0(id, i), label = NULL, value = value[i]))
}
inputs
}

# obtain the values of inputs
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) TRUE else value
}))
}

n = 6
df = data.frame(
cb = shinyInput(checkboxInput, n, 'cb_', value = TRUE, width='1px'),
month = month.abb[1:n],
YN = rep(TRUE, n),
ID = seq_len(n),
stringsAsFactors = FALSE)

loopData = reactive({
df$cb <<- shinyInput(checkboxInput, n, 'cb_', value = shinyValue('cb_', n), width='1px')
df$YN <<- shinyValue('cb_', n)
df
})

output$x1 = DT::renderDataTable(
isolate(loopData()),
escape = FALSE, selection = 'none',
options = list(
dom = 't', paging = FALSE, ordering = FALSE,
preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
))

proxy = dataTableProxy('x1')

observe({
replaceData(proxy, loopData(), resetPaging = FALSE)
})

output$x2 = renderPrint({
data.frame(Like = shinyValue('cb_', n))
})
}
)

Datatable in Shiny with checkboxes and pagination

Here is a way:

library(shiny)
library(DT)

mymtcars <- mtcars
mymtcars[["Select"]] <- paste0('<input type="checkbox" name="row_selected" value=',1:nrow(mymtcars),' checked>')
mymtcars[["_id"]] <- paste0("row_", seq(nrow(mymtcars)))

callback <- c(
sprintf("table.on('click', 'td:nth-child(%d)', function(){",
which(names(mymtcars) == "Select")),
" var checkbox = $(this).children()[0];",
" var $row = $(this).closest('tr');",
" if(checkbox.checked){",
" $row.removeClass('excluded');",
" }else{",
" $row.addClass('excluded');",
" }",
" var excludedRows = [];",
" table.$('tr').each(function(i, row){",
" if($(this).hasClass('excluded')){",
" excludedRows.push(parseInt($(row).attr('id').split('_')[1]));",
" }",
" });",
" Shiny.setInputValue('excludedRows', excludedRows);",
"});"
)

ui = fluidPage(
verbatimTextOutput("excludedRows"),
DTOutput('myDT')
)

server = function(input, output) {

output$myDT <- renderDT({

datatable(
mymtcars, selection = "multiple",
options = list(pageLength = 5,
lengthChange = FALSE,
rowId = JS(sprintf("function(data){return data[%d];}",
ncol(mymtcars)-1)),
columnDefs = list( # hide the '_id' column
list(visible = FALSE, targets = ncol(mymtcars)-1)
)
),
rownames = FALSE,
escape = FALSE,
callback = JS(callback)
)
}, server = FALSE)

output$excludedRows <- renderPrint({
input[["excludedRows"]]
})
}

shinyApp(ui,server, options = list(launch.browser = TRUE))

Sample Image

How can you filter a reactive data table with a checkbox in R shiny without breaking the spread function?

Try this change to your output$table1. Basically, I check if input$checkbox has been given more than one choice; if so, change EventTypes to a constant so that there is only one row

  output$table1 <- renderDataTable({

res <- df() %>%
mutate(EventTypes = gsub("[^a-zA-Z]", "", Event)) %>%
filter(EventTypes %in% input$checkbox)

if(length(input$checkbox)>1) {
res <- mutate(res,EventTypes =paste0(input$checkbox,collapse="/"))
}

res %>% group_by(ID) %>%
add_column(variable = "Thing") %>%
mutate(times = 1:n(),
tot_times = max(times)) %>%
unite(both, variable, times) %>%
spread(both, Event) %>%
arrange(desc(tot_times))
})

Shiny - checkbox in table in shiny

You can use DT with , escape = FALSE see

library(shiny)
library(DT)
mymtcars = mtcars
mymtcars$id = 1:nrow(mtcars)
runApp(
list(ui = pageWithSidebar(
headerPanel('Examples of DataTables'),
sidebarPanel(
checkboxGroupInput('show_vars', 'Columns to show:', names(mymtcars),
selected = names(mymtcars))
,textInput("collection_txt",label="Foo")
),
mainPanel(
DT::dataTableOutput("mytable")
)
)
, server = function(input, output, session) {
rowSelect <- reactive({
paste(sort(unique(input[["rows"]])),sep=',')
})
observe({
updateTextInput(session, "collection_txt", value = rowSelect() ,label = "Foo:" )
})
output$mytable = DT::renderDataTable({
addCheckboxButtons <- paste0('<input type="checkbox" name="row', mymtcars$id, '" value="', mymtcars$id, '">',"")
#Display table with checkbox buttons
DT::datatable(cbind(Pick=addCheckboxButtons, mymtcars[, input$show_vars, drop=FALSE]),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 25, 50),
pageLength = 25,
callback = JS("function(table) {
table.on('change.dt', 'tr td input:checkbox', function() {
setTimeout(function () {
Shiny.onInputChange('rows', $(this).add('tr td input:checkbox:checked').parent().siblings(':last-child').map(function() {
return $(this).text();
}).get())
}, 10);
});
}")),escape = FALSE,

)
}
)
}
)
)

update

Make in other way using shinyinput

library(shiny)
library(DT)
mymtcars = mtcars
mymtcars$id = 1:nrow(mtcars)
runApp(
list(ui = pageWithSidebar(
headerPanel('Examples of DataTables'),
sidebarPanel(
checkboxGroupInput('show_vars', 'Columns to show:', names(mymtcars),
selected = names(mymtcars))
,textInput("collection_txt",label="Foo")
),
mainPanel(
DT::dataTableOutput("mytable")
)
)
, server = function(input, output, session) {

shinyInput <- function(FUN,id,num,...) {
inputs <- character(num)
for (i in seq_len(num)) {
inputs[i] <- as.character(FUN(paste0(id,i),label=NULL,...))
}
inputs
}

rowSelect <- reactive({

rows=names(input)[grepl(pattern = "srows_",names(input))]
paste(unlist(lapply(rows,function(i){
if(input[[i]]==T){
return(substr(i,gregexpr(pattern = "_",i)[[1]]+1,nchar(i)))
}
})))

})

observe({
updateTextInput(session, "collection_txt", value = rowSelect() ,label = "Foo:" )
})
output$mytable = DT::renderDataTable({
#Display table with checkbox buttons
DT::datatable(cbind(Pick=shinyInput(checkboxInput,"srows_",nrow(mymtcars),value=NULL,width=1), mymtcars[, input$show_vars, drop=FALSE]),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 25, 50),
pageLength = 25 ,

drawCallback= JS(
'function(settings) {
Shiny.bindAll(this.api().table().node());}')
),selection='none',escape=F)

}
)

})
)

Shiny: Select single row in DT with checkbox

But I need to only be able to select a single row.

In this case I would not use checkboxes, but radio buttons instead.

Is it OK like this:

library(shiny)
library(DT)

n <- 6
dat <- data.frame(
Select = sprintf(
'<input type="radio" name="rdbtn" value="%s"/>', 1:n
),
YN = rep(FALSE, n),
ID = 1:n,
stringsAsFactors = FALSE
)

callback <- c(
"$('input[name=rdbtn]').on('click', function(){",
" var value = $('input[name=rdbtn]:checked').val();",
" Shiny.setInputValue('rdbtn', value);",
"});"
)

shinyApp(
ui = fluidPage(
title = "Radio buttons in a table",
DTOutput("foo"),
h3("Selected row:"),
verbatimTextOutput("sel")
),
server = function(input, output, session) {
output[["foo"]] <- renderDT(
dat, escape = FALSE, selection = 'none', server = FALSE,
options = list(dom = 't', paging = FALSE, ordering = FALSE),
callback = JS(callback)
)
output[["sel"]] <- renderPrint({
input[["rdbtn"]]
})
}
)

EDIT

Here is a possibility using checkboxes with the Select extension:

library(shiny)
library(DT)

dat <- iris[1:6,]

callback <- c(
"table.on('select', function(e, dt, type, indexes){",
" if(type === 'row'){",
" Shiny.setInputValue('selectedRow', indexes);",
" }",
"});"
)

ui <- fluidPage(
br(),
DTOutput("tbl"),
br(),
h3("Selected row:"),
verbatimTextOutput("selectedRow")
)

server <- function(input, output, session){

output[["tbl"]] <- renderDT({
datatable(dat, extensions = "Select", callback = JS(callback),
options = list(
columnDefs = list(
list(targets = 0, orderable = FALSE, className = "select-checkbox")
),
select = list(
style = "single", selector = "td:first-child"
)
)
)
})

output[["selectedRow"]] <- renderPrint({
input[["selectedRow"]] + 1
})

}

shinyApp(ui, server)

Register shiny checkboxInput value on DT

I thought I had a solution but now I'm afraid I misunderstood your question. With the code below, the values in the value column are updated according to the status of the corresponding checkbox in the value_check column.

js <- c(
"$('[id^=check]').on('click', function(){",
" var id = this.getAttribute('id');",
" var i = parseInt(/check(\\d+)/.exec(id)[1]);",
" var value = $(this).prop('checked');",
" var cell = table.cell(i-1, 2).data(value).draw();",
"})"
)

then

  output$tbl <- renderDT(server = FALSE, escape = FALSE, editable = TRUE, 
callback = JS(js),
options = list(
dom = 't', paging = FALSE, ordering = FALSE,
preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
), {
df$value_check <- shinyInput(checkboxInput, nrow(df), "check")
df
}
)

Sample Image

But now I understand that you ask for the "converse" : check the checkbox according to the value in the value column. Right ? However don't you need the above as well ?

Then, to answer your question as I understand it now, I would do:

shinyCheckboxes <- function(len, id, checked){
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(checkboxInput(paste0(id, i), label=NULL,
value = checked[i]))
}
inputs
}

then

checked <- sapply(df$value, isTRUE)
df$value_check <- shinyCheckboxes(nrow(df), "check", checked)

Is it what you want ?

R Shiny dealing with a dynamic observers list

Try this

  #now I want to disable the ones falling in the third category
#question1: how to iterate on them?
#question2: how to trigger this?

observe({
print(input$chk1)
n <- nrow(mtcarsx())
lapply(1:n, function(i){if(mtcarsx()$mytype[i]=="DISABLED"){ shinyjs::disable(paste0("chk",i)) } })
})

output



Related Topics



Leave a reply



Submit