Unexpected behavior Select All and Deselect All action buttons (R Shiny) - r

I encountered an unexpected behavior. What I intend to do is:
- when users click "Select All," all rows in "Summary Table" get selected. This WORKS. However, the code below doesn't get called.
data <- eventReactive(input$selectAll,{
print("Select All - restore data")
rawdata
})
- on the other hand, when users click "Deselect All," all rows in "Summary Table" get deselected. This WORKS and the code below GETS called.
# Restore data when users click 'Deselect All'
data <- eventReactive(input$deselectAll,{
print("Deselect All - restore data")
rawdata
})
Any idea why?
Here is my full code:
DATASET
colA <- c('A','B','C','D','E')
colB <- c(1,2,3,4,5)
rawdata <- as.data.frame(cbind(colA,colB))
View(rawdata)
server.R
function(input, output, session) {
# Activate tab 'Result' when users click 'Run'
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'result')
})
# Create a dataset based on users' selected variables
data <- eventReactive(input$inputVars_rows_selected,{
print("Select Some Vars")
rawdata[, c(input$inputVars_rows_selected)]
})
# Restore data when users click 'Select All'
data <- eventReactive(input$selectAll,{
print("Select All - restore data")
rawdata
})
# Restore data when users click 'Deselect All'
data <- eventReactive(input$deselectAll,{
print("Deselect All - restore data")
rawdata
})
### VARIABLE SELECTION ####
var <- reactiveValues()
# Select all vars
observeEvent(input$selectAll,{
print("SelectAll ObserveEvent")
var$selected <- 1:nrow(rawdata)
print(var$selected)
})
# Deselect all vars
observeEvent(input$deselectAll,{
print("deselectAll ObserveEvent")
var$selected <- 0
print(var$selected)
print(data())
})
### RESULT TAB ###
result <- eventReactive (input$runButton, {
head(data(),2)
})
### RENDERING FUNCTIONS ###
# Default SummaryTable
output$inputVars <- DT::renderDataTable({
if (input$selectAll==0 & input$deselectAll==0) {
print("Default Summary Table")
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE))
}
else {
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE), selection = list(target = 'row', selected = var$selected))
}
})
# Display results
output$result <- DT::renderDataTable({
DT::datatable(result(), options = list(paging = FALSE, searching = FALSE))
})
output$temp <- renderPrint({
print(input$selectAll)
print(input$deselectAll)
})
}
ui.R
fluidPage(
sidebarPanel(
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel(value='inputVars',title='Variable Selection',
verticalLayout(
DT::dataTableOutput('inputVars'),
br(),
fluidRow(align="bottom",
column(2, actionButton("selectAll" , strong("Select All"))),
column(3, actionButton("deselectAll", strong("Deselect All")))
)
)
),
tabPanel(value='result',title='Result', DT::dataTableOutput('result')),
tabPanel(value='temp',title="TEMP", verbatimTextOutput("temp"))
)
)
)
UPDATED Server.R #2:
#Mike and #HubertL, I think you are right: the issue is caused by eventReactive having cached values. In this updated version, observeEvent corresponding to Select All and Deselect All work as expected. However, now eventReactive corresponding to input$inputVars_rows_selected NEVER gets called. Any idea why?
function(input, output, session) {
# Activate tab 'Result' when users click 'Run'
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'result')
})
data <- reactiveValues()
# Create a dataset based on users' selected variables
data <- eventReactive(input$inputVars_rows_selected,{
print("Select Some Vars")
print(input$inputVars_rows_selected)
rawdata[, c(input$inputVars_rows_selected)]
})
### VARIABLE SELECTION ####
var <- reactiveValues()
# Select all vars
observeEvent(input$selectAll,{
print("SelectAll ObserveEvent")
data <- rawdata
var$selected <- 1:nrow(rawdata)
print(var$selected)
print(data)
})
# Deselect all vars
observeEvent(input$deselectAll,{
print("deselectAll ObserveEvent")
data <- rawdata
var$selected <- 0
print(var$selected)
print(data)
})
### RESULT TAB ###
result <- eventReactive (input$runButton, {
head(data(),2)
})
### RENDERING FUNCTIONS ###
# Default SummaryTable
output$inputVars <- DT::renderDataTable({
if (input$selectAll==0 & input$deselectAll==0) {
print("Default Summary Table")
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE))
}
else {
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE), selection = list(target = 'row', selected = var$selected))
}
})
# Display results
output$result <- DT::renderDataTable({
DT::datatable(result(), options = list(paging = FALSE, searching = FALSE))
})
output$temp <- renderPrint({
print(input$selectAll)
print(input$deselectAll)
print(input$inputVars_rows_selected)
})
}

One reason is because eventReactive is "lazily-evaluated" as opposed to observeEvent which is evaulated immediately.
So in your case the observeEvent corresponding to deselectAll actually uses data(), so that reactiveEvent gets triggered.
# Deselect all vars
observeEvent(input$deselectAll,{
print("deselectAll ObserveEvent")
var$selected <- 0
print(var$selected)
print(data())
})
But the observeEvent corresponding to selectAll does not use data(), so that reactiveEvent does not get triggered:
# Select all vars
observeEvent(input$selectAll,{
print("SelectAll ObserveEvent")
var$selected <- 1:nrow(rawdata)
print(var$selected)
})
I suggest the following changes
If you add a print(data()) here you get some of the behavior you
are seeking.
But it is still not completely right because HubertL's comment that
one definition of data is being overwritten is also valid - and
note that it is not easy to tell where it the data is being pulled.
This is because eventReactive have cached values, so your print
may not show up if a cached value is being used - your code need be
executed to pull that data().
So in any case I would certainly suggest using different names (and
more descriptive) than just repeating "data" to avoid confusion.
Also there is no need to use an eventReactive here, you probably
want a simple reactive. eventReactive is usually needed if you
want to avoid "reactions" from all the other reactive variables in
the code, and I don't see a need for that here.
I would also recommend putting rawdata into a reactiveValues something like this: rv <- reactiveValues(rawdata=rawdata) and then using it as rv$rawdata. This makes it reactive, and then something that uses it will be triggred and recomputed if it ever changes.
See this link (observeEvent vs. eventReactive) for a discussion of the "laziness" of those commands.

Below is the code that works. #Mike and #HubertL were right. The reason is because reactive is lazy vs observeEvent is not. Thanks all for your help!
function(input, output, session) {
# Activate tab 'Result' when users click 'Run'
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'result')
})
data <- reactive({
print("Select Some Vars")
print(input$inputVars_rows_selected)
rawdata[input$inputVars_rows_selected,]
})
### VARIABLE SELECTION ####
var <- reactiveValues()
# Select all vars
observeEvent(input$selectAll,{
print("SelectAll --- ObserveEvent")
var$selected <- 1:nrow(rawdata)
print(var$selected)
print(input$inputVars_rows_selected)
})
# Deselect all vars
observeEvent(input$deselectAll,{
print("deselectAll --- ObserveEvent")
var$selected <- 0
print(var$selected)
})
### RESULT TAB ###
result <- eventReactive (input$runButton, {
head(data(),5)
})
### RENDERING FUNCTIONS ###
# Default SummaryTable
output$inputVars <- DT::renderDataTable({
if (input$selectAll==0 & input$deselectAll==0) {
print("Default Summary Table")
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE))
}
else {
DT::datatable(rawdata, options = list(paging = FALSE, searching = FALSE), selection = list(target = 'row', selected = var$selected))
}
})
# Display results
output$result <- DT::renderDataTable({
DT::datatable(result(), options = list(paging = FALSE, searching = FALSE))
})
output$temp <- renderPrint({
print(input$selectAll)
print(input$deselectAll)
print(input$inputVars_rows_selected)
})
}

Related

How to use action buttons to show and hide table output in R shiny?

In the below simple App code, I generate a user input table (or matrix) inside a Shiny modal dialog. Clicking the "Modify" action button pulls up a default user input table where the user can modify the default values, insert/delete input columns, etc. "Show" action button pulls up table2 in the main page, "Hide" hides that same table. (You can ignore the table1 that appears in the modal box, that's temporarily there for testing purposes, to be deleted later). "Reset" button reverts the table back to the default table.
Problem with this is "Show" and "Hide" work only once. Also, after having modified the input table (or matrix), clicking "Modify" pulls up the default table and not the most recently modified table.
So, how would I modify the below so that (i) clicking "Show" and "Hide" respectively show and hide the most recently modified table, repeatedly (OK to have a combined Show/Hide button too, using shinyjs toggle function, something I have toyed with), (ii) clicking "Modify" the first time the App is invoked pulls up the default table (as it currently does) but subsequent clicks of "Modify" pull up the most recently modified table, and (iii) clicking "Show" without having first modified the table pulls up the default table?
MWE code:
library(shiny)
library(shinyMatrix)
library(shinyjs)
matrix3Input <- function(x){
matrixInput(x,
label = 'Series terms:',
value = matrix(c(1,24,0,1),4,1,dimnames=list(c("A","B","C","D"),NULL)),
rows = list(extend = FALSE,names = TRUE),
cols = list(extend = TRUE,names = TRUE,editableNames = TRUE,delete = TRUE),
class = "numeric") # close matrix input
} # close function
ui <- fluidPage(
useShinyjs(),
titlePanel("Inputs"),
fluidRow(actionButton("modify","Modify"),
actionButton("show","Show"),
actionButton("hide","Hide"),
actionButton("reset","Reset"),
tableOutput("table2")
) # close fluid row
) # close fluid page
server <- function(input, output, session) {
observeEvent(input$modify,{showModal(modalDialog(
matrix3Input("matrix"),
tableOutput("table1"))
)})
output$table1 <- renderTable(input$matrix, rownames = TRUE)
observeEvent(input$show,{
tableOutput("table2")
output$table2 <- renderTable(input$matrix, rownames = TRUE)
})
observeEvent(input$hide,{hide("table2")})
observeEvent(input$reset,{
tableOutput("table2")
output$table2 <- renderTable(input$matrix, rownames = TRUE)
})
} # close server
shinyApp(ui, server)
I think this should cover for all the different scenarios.
I have used reactiveValues to save matrix3Input and matrix.
library(shiny)
library(shinyMatrix)
library(shinyjs)
default_mat <- matrix(c(1,24,0,1),4,1,dimnames=list(c("A","B","C","D"),NULL))
matrix3Input <- function(x, default_mat){
matrixInput(x,
label = 'Series terms:',
value = default_mat,
rows = list(extend = FALSE,names = TRUE),
cols = list(extend = TRUE,names = TRUE,editableNames = TRUE,delete = TRUE),
class = "numeric") # close matrix input
} # close function
ui <- fluidPage(
useShinyjs(),
titlePanel("Inputs"),
fluidRow(actionButton("modify","Modify"),
actionButton("show","Show"),
actionButton("hide","Hide"),
actionButton("reset","Reset"),
tableOutput("table2")
) # close fluid row
) # close fluid page
server <- function(input, output, session) {
rv <- reactiveValues(mat = matrix3Input("matrix", default_mat), input = default_mat)
hide("table2")
observeEvent(input$modify,{
showModal(modalDialog(
rv$mat,
tableOutput("table1"))
)
hide("table2")
})
output$table1 <- renderTable({
rv$mat <- matrix3Input("matrix", input$matrix)
rv$input <- input$matrix
input$matrix
}, rownames = TRUE)
observeEvent(input$show,{
show("table2")
})
observeEvent(input$hide, hide("table2"))
observeEvent(input$reset,{
hide("table2")
rv$input <- default_mat
rv$mat <- matrix3Input("matrix", default_mat)
})
output$table2 <- renderTable({
rv$input
}, rownames = TRUE)
} # close server
shinyApp(ui, server)

How to excract data from edited datatable in shiny

I want to creat an shiny app where users have to edit datatable.
There is the code contains reproductible exemple:
library(shiny)
library(dplyr)
library(DT)
line<-c(1,1,1,1,1)
op<-c(155,155,155,156,156)
batch<-c(1,2,3,1,2)
voile<-c(1,NA,NA,NA,NA)
depot<-c(2,NA,2,NA,NA)
boe<-data.frame(line,op,batch)
ui <- fluidPage(
# Application title
titlePanel("test dust"),
actionButton("refresh", label = "refresh"),
DT::dataTableOutput("mytable"),
actionButton("save", label = "save"),
)
# Define server logic required to draw a histogram
server <- function(input, output) {
DTdust<- eventReactive(input$refresh, {
DTdust <-data.frame(line,op,batch,voile,depot)
})
merged<-reactive({
merged<-merge(boe,DTdust(),all.x = TRUE)
})
mergedfiltred<-reactive({
mergedfiltred<- filter(merged(),is.na(voile)|is.na(depot) )
})
output$mytable = DT::renderDataTable( mergedfiltred(),editable = list(target = 'cell',
disable = list(columns = c(1:3))),selection = 'none'
)
}
# Run the application
shinyApp(ui = ui, server = server)
I wish this works like this —>
When user clic on refresh button. Dtdust.csv (here simulated) is read , then it merged with boe.csv (simulated too) an filter to get only rows without resulta for voile and depot col.
And display this merged filtred ino editable datatable .
This part works.
After i want to extract the data from edited datatable to make some processing on it (extract rows completed, rbind it on dtdust and save as dtdust.csv. But that’s ok i think.)
I’ m in trouble to extract edited datatable.
I see some exemple to do it with classic dataframe but it not work with reactive one.
I’m beeginner so if you can comment a lot your answers i can learn how to and not just ctrl+c ctrl+v your code :)
Thanks
You need to define a reactiveValues data frame. Then you need to update it via observeEvent whenever any cell is modified via mytable_cell_edit. The updated dataframe is now available in the server side, and part of it is now printed in the second table. You can use DF1$data for further analysis or subsetting. Full updated code is below.
library(shiny)
library(dplyr)
library(DT)
line<-c(1,1,1,1,1)
op<-c(155,155,155,156,156)
batch<-c(1,2,3,1,2)
voile<-c(1,NA,NA,NA,NA)
depot<-c(2,NA,2,NA,NA)
boe<-data.frame(line,op,batch)
ui <- fluidPage(
# Application title
titlePanel("test dust"),
actionButton("refresh", label = "refresh"),
DTOutput("mytable"), DTOutput("tb2"),
actionButton("save", label = "save"),
)
# Define server logic required to draw a histogram
server <- function(input, output) {
DF1 <- reactiveValues(data=NULL)
DTdust<- eventReactive(input$refresh, {
req(input$refresh)
DTdust <-data.frame(line,op,batch,voile,depot)
})
merged<-reactive({
req(DTdust())
merged<-merge(boe,DTdust(),all.x = TRUE)
})
mergedfiltred<-reactive({
mergedfiltred <- filter(merged(),is.na(voile)|is.na(depot) )
DF1$data <- mergedfiltred
mergedfiltred
})
output$mytable = renderDT(
mergedfiltred(),
editable = list(target = 'cell', disable = list(columns = c(1:3))), selection = 'none'
)
observeEvent(input$mytable_cell_edit, {
info = input$mytable_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
DF1$data[i, j] <<- DT::coerceValue(v, DF1$data[i, j])
})
output$tb2 <- renderDT({
df2 <- DF1$data[,2:5]
plen <- nrow(df2)
datatable(df2, class = 'cell-border stripe',
options = list(dom = 't', pageLength = plen, initComplete = JS(
"function(settings, json) {",
"$(this.api().table().header()).css({'background-color': '#000', 'color': '#fff'});",
"}")))
})
}
# Run the application
shinyApp(ui = ui, server = server)
Hi thanks for your solution #YBS.
I finaly find a solution by myself half an hour after asking here... (i previously turning arround hours and hours).
There is what i do :
output$x2 = DT::renderDataTable({
req(dat$x2)
DT::datatable(dat$x2)
})
dat <- reactiveValues()
# update edited data
observeEvent(input$mytable_cell_edit, {
data_table <- dat$x2
data_table[input$mytable_cell_edit$row, input$mytable_cell_edit$col] <- as.numeric(input$mytable_cell_edit$value)
dat$x2 <- data_table
})
Have a good day

Use Shiny ActionButton to select all rows or add all rows to selection in current view with filtering in a DT datatable

I have been trying to create ActionButtons to allow a user to 'Select all rows in view' in a reactive, filtering datatable.
Currently the button does this using tableid_rows_current; however, I also want to add in a table proxy so that it doesn't reset to the first page of results if you're on another page, but I can't figure out the syntax after much googling (see attempts commented out in code). Also if you manually select some rows, it no longer works.
Another ActionButton that allows a user to 'add all rows in view to selection'. That is to add all current rows in view to your previous selection. This one I'm not even sure where to start, so any ideas are appreciated.
(Not included here, but I do have functioning 'clear selection' and 'clear filter' buttons already, if anyone is interested)
Minimum reproducible code below. The app is meant to display the images for the selected rows, but not a big deal here that you won't have actual images displaying.
library(DT)
library(shiny)
dat <- data.frame(
type = c("car", "truck", "scooter", "bike"),
frontimage = c("carf.jpg", "truckf.jpg", "scooterf.jpg", "bikef")
)
# ----UI----
ui <- fluidPage(
titlePanel("Buttons 'select all' and 'add to select'"),
mainPanel(
DTOutput("table"),
actionButton("select_all_current", "Select All Rows in View"),
actionButton("add_to_selection", "Add All Rows in View to Selection"),
uiOutput("img1")
)
)
# ----Server----
server = function(input, output, session){
# Action button to select all rows in current view
var <- reactiveValues()
tableProxy <- dataTableProxy('table')
observeEvent(input$select_all_current, {
print("select_all_current")
# tableProxy %>% selectRows(1:nrow(input$table_rows_current))
# var$selected <- tableProxy %>% input$table_rows_current
tableProxy <- #I want the table proxy to be whatever the current selection and filters are and the current page view to stay the same after selecting
var$selected <- input$table_rows_current
})
# Action button to add all rows in current view to previous selection
observeEvent(input$add_to_selection, {
print("select_all_current")
})
# Data table with filtering
output$table = DT::renderDT({
datatable(dat, filter = list(position = "top", clear = FALSE),
selection = list(target = 'row', selected = var$selected),
options = list(
autowidth = TRUE,
pageLength = 2,
lengthMenu = c(2, 4)
))
})
# Reactive call that only renders images for selected rows
df <- reactive({
dat[input[["table_rows_selected"]], ]
})
# Front image output
output$img1 = renderUI({
imgfr <- lapply(df()$frontimage, function(file){
tags$div(
tags$img(src=file, width="100%", height="100%")
)
})
do.call(tagList, imgfr)
})
}
# ----APP----
# Run the application
shinyApp(ui, server)
Does this do what you're looking for?
library(DT)
library(shiny)
dat <- data.frame(
type = c("car", "truck", "scooter", "bike"),
frontimage = c("carf.jpg", "truckf.jpg", "scooterf.jpg", "bikef")
)
# ----UI----
ui <- fluidPage(
titlePanel("Buttons 'select all' and 'add to select'"),
mainPanel(
DTOutput("table"),
actionButton("select_all_current", "Select All Rows in View"),
actionButton("add_to_selection", "Add All Rows in View to Selection"),
uiOutput("img1")
)
)
# ----Server----
server = function(input, output, session){
# Action button to select all rows in current view
var <- reactiveValues()
tableProxy <- dataTableProxy('table')
observeEvent(input$select_all_current, {
print("select_all_current")
# tableProxy %>% selectRows(1:nrow(input$table_rows_current))
# var$selected <- tableProxy %>% input$table_rows_current
# tableProxy <- #I want the table proxy to be whatever the current selection and filters are and the current page view to stay the same after selecting
# var$selected <- input$table_rows_current
selectRows(proxy = tableProxy,
selected = input$table_rows_current)
})
# Action button to add all rows in current view to previous selection
observeEvent(input$add_to_selection, {
print("select_all_current")
selectRows(proxy = tableProxy,
selected = c(input$table_rows_selected, input$table_rows_current))
})
# Data table with filtering
output$table = DT::renderDT({
datatable(dat, filter = list(position = "top", clear = FALSE),
selection = list(target = 'row'),#, selected = var$selected),
options = list(
autowidth = TRUE,
pageLength = 2,
lengthMenu = c(2, 4)
))
})
# Reactive call that only renders images for selected rows
df <- reactive({
dat[input[["table_rows_selected"]], ]
})
# Front image output
output$img1 = renderUI({
imgfr <- lapply(df()$frontimage, function(file){
tags$div(
tags$img(src=file, width="100%", height="100%")
)
})
do.call(tagList, imgfr)
})
}
# ----APP----
# Run the application
shinyApp(ui, server)

Update datatable with selectInput and insert to the database

Trying to use selectInput in a form.
the choices are fetched from a collection in mongodB.
when user
completes the form and submits (which inserts to another collection
in mongo), data in selectInput is not captured.
tried to make it reactive or use observeEvent /updateSelectInput in the server but could not make it work.
here is the entire code:
library(shiny)
library(mongolite)
library(jsonlite)
# which fields get saved
fieldsAll <- c("Name", "selectOne", "tags")
saveData <- function(data) {
# Connect to the database
}
# load all responses into a data.frame
loadData <- function() {
# Connect to the database
}
fetchData <- function() {
# Connect to the database
}
shinyApp(
ui = tagList(
navbarPage(
tabPanel("Technology",
sidebarPanel(
textInput("Name",label ='Name:'),
selectInput('selectOne',
label ='Select One:',
choices=head(fetchData()),
selected = "",
multiple = FALSE),
selectizeInput("tags", "Tags:", NULL, multiple = TRUE, options=list(create=TRUE)),
actionButton("submit", "Submit", class = "btn-primary")
),
mainPanel(
tabsetPanel(
tabPanel("Table",
uiOutput("adminPanelContainer")
)
)
)
)
)
),
server = function(input, output, session) {
formData <- reactive({
fieldsAll
data <- sapply(fieldsAll, function(x) input[[x]])
data <- t(data)
data
})
observeEvent(input$submit, {
saveData(formData())
},
)
# render the admin panel
output$adminPanelContainer <- renderUI({
DT::dataTableOutput("responsesTable")
})
# Update the responses table whenever a new submission is made
responses_data <- reactive({
input$submit
data <- loadData()
data
})
# Show the responses in the admin table
output$responsesTable <- DT::renderDataTable({
DT::datatable(
responses_data(),
rownames = FALSE,
options = list(searching = TRUE, lengthChange = FALSE)
)
})
}
)
adding a column to the df with selected value worked:
formData <- reactive({
fieldsAll
data <- sapply(fieldsAll, function(x) input[[x]])
data <- c(data,selectOne= input$selectOne) #added line
data <- t(data)
data
})

Shiny: Making RHandsontable read only on click

I want to make my rhandsontable read only on clicking the action button 'Freeze Forecast' and activate the table on clicking on 'Edit Forecast'. It should show me the Sum Output on clicking on 'Generate Forecast' button.
Please help to correct my existing code as per above conditions.
UI.R
packages <- c( "shiny", "data.table", "devtools", "shinysky","googleVis","scales","rhandsontable" )
lapply( packages, require, character.only = TRUE )
jsResetCode <- "shinyjs.reset = function() {history.go(0)}" #JS Code to refresh the App
did_recalc <- FALSE
ui <- fluidPage(
# Application title
titlePanel("Scenario Planner Test App"),
br(),br(),
actionButton("recalc", "Generate Forecast"),
actionButton("edit", "Edit Forecast"),
actionButton("freeze", "Freeze Forecast"),br(),br(),
rHandsontableOutput('table'),br(),br(),
textOutput('restitle'),
textOutput('result')
)
Server.R
Sys.setenv(R_ZIPCMD="/usr/bin/zip")
packages <- c( "shiny", "data.table", "devtools", "shinysky","googleVis","scales","reshape2" )
lapply( packages, require, character.only = TRUE )
disableActionButton <- function(id,session) {
session$sendCustomMessage(type="jsCode1",
list(code= paste("$('#",id,"').prop('disabled',true)"
,sep="")))
}
enableActionButton <- function(id,session) {
session$sendCustomMessage(type="jsCode2",
list(code= paste("$('#",id,"').prop('disabled',false)"
,sep="")))
}
shiny::shinyServer( function(input,output,session)({
values <- reactiveValues(data=as.data.frame(runif(2)))
observe({
input$recalc
values$data <- as.data.frame(runif(2))
})
observe({
if(!is.null(input$table))
values$data <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
rhandsontable(values$data)
})
observe({
input$freeze
print("freeze")
##if(!is.null(input$table))
print("2freeze")
rhandsontable(values$data) %>%
hot_table(readOnly = TRUE)
})
output$restitle <- renderText({
"Sum Output"
})
output$result <- renderText({
sum(values$data)
})
})
)
I got this to work by
Adding a state variable to your reactive called readonly
Adding two observerEvent routines to the edit and freeze action buttions to toggle readonly.
Modifying your output$table command to use the reactive readonly variable.
It would have been easier, and not needed a lot of those elements if you had just used a checkbox to indicate that the table is editable, and then wired that variable to the readOnly parameter, but sometimes you need to do it this way, so I solved it like this.
The complete server.R code is here:
packages <- c("shiny","data.table","devtools","shinysky","googleVis","scales","reshape2")
lapply(packages,require,character.only = TRUE)
disableActionButton <- function(id,session) {
session$sendCustomMessage(type = "jsCode1",
list(code = paste("$('#",id,"').prop('disabled',true)"
,sep = "")))
}
enableActionButton <- function(id,session) {
session$sendCustomMessage(type = "jsCode2",
list(code = paste("$('#",id,"').prop('disabled',false)"
,sep = "")))
}
shiny::shinyServer(function(input,output,session)({
values <- reactiveValues(data = as.data.frame(runif(2)),readonly=FALSE)
observe({
input$recalc
values$data <- as.data.frame(runif(2))
})
observe({
if (!is.null(input$table))
values$data <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
rhandsontable(values$data,readOnly=values$readonly)
})
observeEvent(input$edit, {
values$readonly <- FALSE
})
observeEvent(input$freeze,{
values$readonly <- TRUE
})
output$restitle <- renderText({
"Sum Output"
})
output$result <- renderText({
sum(values$data)
})
})
)
and it looks like this:

Resources