I am using rhandsonpackage and am using solution from below link from this to achieve following scenario - "The change of drop down should present user with a different set of input, that they further may modify, while some other columns continue recalculating"
R Shiny App: Reactive/Calculate column in Rhandsontable
It works perfectly when the initial DF(initialized as previous <- reactive({DF})) is static.
However if DF is dynamic and lets say different based on a dropdown selection, the logic doesn't work.
The core reason is that inside 'MyChanges' definition, even when this dynamic DF is updated, object keeps on working the old input$hotable1 (since the is.null(input$hotable1) condition is never met again). Hence although the dynamic DF is updated correctly in 'previous', it won't reflect in the 'MyChanges'. I tried setting a flag to capture when the dropdown changes and setting the input$hottable1 to NULL but it's a read only object and that operation errors out.
Here is the modified code snippet to reproduce the issue. Again, main issues is that at line 26, it ignores the updated 'previous()' object. Really appreciate any help with a resolution on this!
#rm(list = ls())
library(shiny)
library(rhandsontable)
library(shinyWidgets)
## Create the dataset
getdynamicDF <- function(selection){
if(selection=="a"){return(data.frame(num = 1:10, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
else if (selection=="b"){return(data.frame(num = 11:20, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
else if (selection=="c"){return(data.frame(num = 21:30, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
}
# DF = data.frame(num = 1:10, price = 1:10,Total = 1:10,stringsAsFactors = FALSE)
numberofrows <- 10
server <- shinyServer(function(input, output, session) {
# Initiate your table
# dynamicDF <- function(option)
previous <- reactive({
getdynamicDF(input$mydropdown)
})
MyChanges <- reactive({
if(is.null(input$hotable1)){return(previous())}
else if(!identical(previous(),input$hotable1)){
# hot.to.df function will convert your updated table into the dataframe
mytable <- as.data.frame(hot_to_r(input$hotable1))
# here the second column is a function of the first and it will be multipled by 100 given the values in the first column
mytable <- mytable[1:numberofrows,]
# Add some test cases
mytable[,1][is.na(mytable[,1])] <- 1
mytable[,2][is.na(mytable[,2])] <- 1
mytable[,3] <- mytable[,1]*mytable[,2]
mytable
}
})
output$hotable1 <- renderRHandsontable({rhandsontable(MyChanges())})
})
ui <- basicPage(mainPanel(pickerInput(
inputId = "mydropdown",
label = "Option",
choices = c("a", "b", "c")
),
rHandsontableOutput("hotable1")))
shinyApp(ui, server)
Perhaps this is what you are looking for.
library(shiny)
library(rhandsontable)
library(shinyWidgets)
## Create the dataset
getdynamicDF <- function(selection){
if(selection=="a"){return(data.frame(num = 1:10, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
else if (selection=="b"){return(data.frame(num = 11:20, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
else if (selection=="c"){return(data.frame(num = 21:30, price = 1:10,Total = 1:10,stringsAsFactors = FALSE))}
}
#numberofrows <- 10
server <- shinyServer(function(input, output, session) {
new <- reactiveValues(dt=NULL)
previous <- eventReactive(input$mydropdown, {
req(input$mydropdown)
getdynamicDF(input$mydropdown)
})
observe({new$dt<-previous()})
observeEvent(input$hotable1, {
mytable <- as.data.frame(hot_to_r(input$hotable1))
mytable[,3] <- mytable[,1]*mytable[,2]
new$dt <- mytable
})
output$hotable1 <- renderRHandsontable({
rhandsontable(new$dt)
})
})
ui <- basicPage(mainPanel(pickerInput(
inputId = "mydropdown",
label = "Option",
choices = c("a", "b", "c")
),
rHandsontableOutput("hotable1")))
shinyApp(ui, server)
Related
Hi I'm relatively new to Shiny and am not sure how to do this. I am making a dashboard that should first pull the relevant dataframe based on user selectInput, after which further selectInput functions will further filter down the sheet for the relevant price. However, I can't seem to link the InputId from the selectInput to the relevant dataframe name. (Below is code)
UI.R
ui <- navbarPage(
"Dashboard",
tabPanel(
"Cost1",
fluidPage(
selectInput("type",
label = "Select Type",
choices = NULL),
textOutput("message")
)
)
)
Server.R
#load libraries, data
library(tidyr)
library(readxl)
library(dplyr)
library(purrr)
a <- read_excel('source.xlsx', sheet = 'a')
b <- read_excel('source.xlsx', sheet = 'b')
c <- read_excel('source.xlsx', sheet = 'c')
mylist <- list(a = a, b = b, c = c)
server <- function(input, output, session) {
updateSelectInput(session,
"type",
choices = names(mylist))
material = reactive(input$type)
price <- material[1,"price"]
output$message <- renderText({
paste(price)
})
}
Thank you!
There is a few things that need to correct in your original code - here is my code for 3 files global.R, server.R, and ui.R with detail explanation comments. (my habit of separating them so it easier to manage.
global.R
#load libraries, data
library(shiny)
library(tidyr)
library(readxl)
library(dplyr)
library(purrr)
# This is just a generation of sample data to be used in this answer.
set.seed(1)
generate_random_df <- function(name) {
tibble(
product = paste0(name, "-", round(runif(n = 10, min = 1, max = 100))),
price = runif(10))
}
a <- generate_random_df("a")
b <- generate_random_df("b")
c <- generate_random_df("c")
mylist <- list(a = a, b = b, c = c)
server.R
set.seed(1)
generate_random_df <- function(name) {
tibble(
product = paste0(name, "-", round(runif(n = 10, min = 1, max = 100))),
price = runif(10))
}
a <- generate_random_df("a")
b <- generate_random_df("b")
c <- generate_random_df("c")
mylist <- list(a = a, b = b, c = c)
server <- function(input, output, session) {
updateSelectInput(session,
"type",
choices = names(mylist))
# to extract the data you need to reference to mylist as the Input only take
# the name of your list not the dataset within it
price <- reactive({
# Here the material command also inside the reactive not as you do initially
material <- mylist[[input$type]]
paste0(material[1,"price"])
})
# You don't need renderText for this just assign the value to message
output$message <- price
# I also output the table for easier to see
output$price_table <- renderTable(mylist[[input$type]])
}
ui.R
ui <- navbarPage(
"Dashboard",
tabPanel(
"Cost1",
fluidPage(
selectInput("type",
label = "Select Type",
choices = NULL),
textOutput("message"),
tableOutput("price_table")
)
)
)
Here is the screenshot of the app
I am building app where a user can make edits to a datatable and the hit a button to reflect the changes in a non-editable copy of this datatable (in the final project, I will need to have two datasets that need to be matched manually), but for now this small MWE shows the problem I have with making a copy of the reactive table in which changes can be made, without changing the data of the original reactive table. I would like to make this app work, where you click edit a cell in the table dat_joined$data/output$mytable and that those changes do reflect in a new table mydf$data/output$table2. To do mydf$data initially (before any changes are made) needs to be a copy of dat_joined$data This is a follow up on this question and answer: how to make a copy of a reactive value in shiny server function
library(shiny)
library(DT)
library(shinyWidgets)
library(tidyverse)
# create master dataframe
dat_total <- tibble(ID_1 = 1:10, names = letters[1:10],
ID_2 = 11:20, names_2 = LETTERS[c(3:5, 1, 2, 6:8, 10, 9)])
shinyApp(
ui = fluidPage(
title = 'Radio button and a dropdown manue ',
sliderInput("n_rows_table", "Number of rows:",
min = 0, max = 10,
value = 5),
actionBttn(
inputId = "button_1",
label = "Make tables",
size = "sm",
color = "warning"
),
DT::dataTableOutput("mytable"),
actionBttn(
inputId = "button_2",
label = "Process",
size = "sm",
color = "success"),
DT::dataTableOutput("table2")),
server = function(input, output, session) {
# set up reactive values
dat_left <- reactiveValues(data=NULL)
dat_right <- reactiveValues(data=NULL)
dat_joined <- reactiveValues(data=NULL)
# create reactive daraframe
dat <- eventReactive(input$button_1, {
dat_total[1:input$n_rows_table, ] %>%
rowid_to_column()})
# Split the data into a right and a left set
observe({
dat_left$data <- dat() %>%
select(rowid, ID_1, names)
})
observe({
dat_right$data <- dat() %>%
select(rowid, ID_2, names_2,ID_1)
})
# join these again
# This is needed because my actual app will
# be used to manually match 2 datasets
observe({
if (is.null( dat_right$data )) {
NULL
}else{
dat_joined$data <- left_join(dat_left$data,
dat_right$data,
by = "rowid")
}
})
# Print the the datasets
output$mytable <- renderDT({
datatable(dat_joined$data ,
rownames = F,
editable = "cell")
})
# I want to make a copy of the dat_joined$data dataset into dat$mydf
# none of these function as expected
#mydf <- reactiveValues(data=isolate(dat_joined$data))
#mydf <- reactiveValues(data=local(dat_joined$data))
#mydf <- reactiveValues(data=dat_joined$data)
#mydf <- reactiveValues(data=NULL)
# This works, but only saves the cells to w
mydf <- reactiveValues(data=matrix(NA, nrow=10, ncol = 5))
# Ideally the computation only happens when this both an edit is made
# and the button is pressed (now I need to press it between every edit)
# validate_event <- reactive({
# req(input$mytable_cell_edit) & req(input$button_2)
# })
#observeEvent(input$button_2validate_event(), { DOes not work
observeEvent(input$button_2,{
info = input$mytable_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
mydf$data[i, j] <- DT::coerceValue(v, mydf$data[i, j])
})
# print
output[["table2"]] <- renderDT({
datatable(mydf$data)
})
}
)
Any changes you make in the top table is reflected in the bottom table after you press the button "Process". Try this
library(shiny)
library(DT)
library(shinyWidgets)
library(tidyverse)
# create master dataframe
dat_total <- tibble(ID_1 = 1:10, names = letters[1:10],
ID_2 = 11:20, names_2 = LETTERS[c(3:5, 1, 2, 6:8, 10, 9)])
shinyApp(
ui = fluidPage(
title = 'Radio button and a dropdown manue ',
sliderInput("n_rows_table", "Number of rows:",
min = 0, max = 10,
value = 5),
actionBttn(
inputId = "button_1",
label = "Make tables",
size = "sm",
color = "warning"
),
DT::dataTableOutput("mytable"),
actionBttn(
inputId = "button_2",
label = "Process",
size = "sm",
color = "success"),
DT::dataTableOutput("table2")),
server = function(input, output, session) {
# set up reactive values
dat_left <- reactiveValues(data=NULL)
dat_right <- reactiveValues(data=NULL)
dat_joined <- reactiveValues(data=NULL)
dfon <- reactiveValues(top=NULL,
bottom=NULL)
# create reactive daraframe
dat <- eventReactive(input$button_1, {
dat_total[1:input$n_rows_table, ] %>%
rowid_to_column()})
# Split the data into a right and a left set
observe({
req(dat())
dat_left$data <- dat() %>%
dplyr::select(rowid, ID_1, names)
})
observe({
req(dat())
dat_right$data <- dat() %>%
dplyr::select(rowid, ID_2, names_2,ID_1)
})
# join these again
# This is needed because my actual app will
# be used to manually match 2 datasets
observe({
req(dat())
if (!is.null( dat_right$data )) {
dat_joined$data <- left_join(dat_left$data,
dat_right$data,
by = "rowid")
}
})
observe({ ###assign your orig data to a reactiveValues object
req(dat_joined$data)
if (!is.null(dat_joined$data)) {
dfon$top <- dat_joined$data
}
})
# Print the the datasets
output$mytable <- renderDT({
datatable(dfon$top,
rownames = F,
editable = "cell")
})
# Ideally the computation only happens when this both an edit is made
# and the button is pressed (now I need to press it between every edit)
observeEvent(input$mytable_cell_edit, {
info = input$mytable_cell_edit
str(info)
#i = info$row
#j = info$col + 1 # offset by 1
#v = info$value
#dfon$top[i, j] <<- DT::coerceValue(v, dfon$top[i, j])
dfon$top <<- editData(dfon$top, info)
})
observeEvent(input$button_2,{
dfon$bottom <- dfon$top
output$table2 <- renderDT({
datatable(dfon$bottom)
})
})
## further editing of dfon$bottom is performed below...with...observeEvent(input$table2_cell_edit, {...
}
)
In the output below, I have entered cccc for 3rd element in names column, but I have not clicked on the button Process. Therefore, the edited cell is not reflected in the bottom table.
Issues I am having couple of issues with (a) Display the data in interactive mode using Rshiny (2) Querying the results from mongodb Query. My codes are given below, it seems to work as independent pieces but doesnt coalesce well.
For Problem (a), I have previously used Output$values and that seems to work. Commented out in the code
For Problem (b), I have used mongolite R package to query the data and used reactive for passing the query.
library(data.table)
library(tidyverse)
library(shiny)
library(mongolite)
epi <- read.csv("./data/Genes.csv", header=T)
label = "gene"
epilist <- data.frame(epi$gene, label)
names(epilist) = c("value", "label")
df <- read.table("./data/CCLE_meta.csv", header=TRUE, sep=",", na.strings="NA", fill=TRUE)
dd <- data.frame((df$Tissue))
names(dd) = "Tissue"
cell1= dd %>% add_row(Tissue = "all")
label = "Tissue"
cell <- data.frame(cell1$Tissue, label)
names(cell) = c("value", "label")
ui <- fluidPage(
titlePanel("Dependencies for EpiGenes"),
sidebarLayout(
sidebarPanel(
selectizeInput("epiInput","gene", choices=NULL, selected=NULL),
selectizeInput("cellInput","Tissue", choices=NULL, selected=NULL),
textOutput("values")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Fusions", tableOutput("table")),
tabPanel("CancerGD", tableOutput("table")),
tabPanel("CCLEmeta", tableOutput("table")),
tabPanel("EpiGenes", tableOutput("table"))
)
)
)
)
server <- function(input, output, session) {
updateSelectizeInput(session, 'epiInput',
choices = epilist$value,
server = TRUE)
updateSelectizeInput(session, 'cellInput',
choices = cell$value,
server = TRUE)
#output$values <- renderText({
# paste(input$epiInput, input$cellInput)
#})
### Looking into Epi Genes
con1 <- mongo(collection = "Genes", db = "discovery", url = "mongodb://127.0.0.1:27017")
data.for.table1 <- reactive({
query.foo <- paste0('{"gene" : epiInput}')
con1$find(query = query.foo, limit = 100)
})
output$EpiGenes <- renderDataTable({
data.for.table1()
})
### Looking into Cell Line Metadata
con0 <- mongo(collection = "CellLine", db = "discovery", url = "mongodb://127.0.0.1:27017")
data.for.table0 <- reactive({
query.foo <- paste0('{"Tissue" : input$cellInput}')
con0$find(query = query.foo, limit = 100)
})
output$CCLEmeta <- renderDataTable({
data.for.table0()
})
### Looking into fusion genes
con2 <- mongo(collection = "fusions", db = "discovery", url = "mongodb://127.0.0.1:27017")
data.for.table2 <- reactive({
query.foo <- paste0('{"gene" : input$epiInput}')
con2$find(query = query.foo, limit = 100)
})
output$Fusions <- renderDataTable({
data.for.table2()
})
### Looking into CancerGD
con3 <- mongo(collection = "CancerGD", db = "discovery", url = "mongodb://127.0.0.1:27017")
data.for.table3 <- reactive({
query.foo <- paste0('{"gene" : input$epiInput}')
con3$find(query = query.foo, limit = 100)
})
output$CancerGD <- renderDataTable({
data.for.table3()
})
# Automatically disconnect when connection is removed
rm(con0)
rm(con1)
rm(con2)
rm(con3)
gc()
}
shinyApp(ui, server)
The first expected output is an app to allow users to query from the list of genes and tissue. The second expected output is display query results in its appropriate tab (From 4 collections from database discovery). The current result is an app with no ability to query.
I was able to make some changes to the code and the error/hanging I now get is
"Imported 0 records. Simplifying into dataframe..."
Any insight into the error will be helpful.
The improvements to the codes are as follows;
(a) SidebarPanel
selectizeInput("epiInput","gene", choices=gg),
selectizeInput("cellInput","Tissue", choices=cc),
(b) Connecting to MongoDB
con2 <- mongo(collection="fusions", db="discovery", url="mongodb://localhost:27017", verbose = TRUE)
fusResults <- reactive({
region <- list(gene = input$epiInput)
query.foo <- paste0('{ "gene" : "',region , '"}')
fs <- con2$find(query = query.foo, limit = 100)
return(fs)
})
output$fus_results <- renderDataTable({
fusResults()
})
People!
If i have the following data frame:
observeEvent(input$pesquisa,{
query <- glue(
"select
cod_ordem_producao as ORDEM,
dim_ext_tubo as DIAMETRO,
esp_par_tubo as PAREDE,
cod_aqa as AQA,
tmo_ciclo_plan as CICLO,
dth_criacao_reg as DATA,
dsc_aco as GRAU,
val_lim_escoamento as LE,
val_tensao_residual as TR
from
QT_QTS.PLA_ORDEM_PRODUCAO
where DIM_EXT_TUBO = {as.numeric(input$diametro)}
and esp_par_tubo = {as.numeric(input$parede)}
and tmo_ciclo_plan = {as.numeric(input$ciclo)}
and dth_criacao_reg between DATE '{as.character(input$dates[1])}' and DATE '{as.character(input$dates[2])}'
and VAL_LIM_ESCOAMENTO != 0
order by DTH_CRIACAO_REG desc")
df <- dbGetQuery(
connection_reportUser,
query
)
df <-------------- HERE IS THE SAVED VALUES TO THE DATA FRAME---------------
valor_grau <- df$GRAU
})
And, next, I use another observeEvent:
observeEvent(input$pesquisa, {
insertUI(
selector = "#pesquisa",
where = "afterEnd",
ui = selectInput(
"grau",
label = "Grau:",
choices = valor_grau
)
)
})
Explaining:
I search in a database these values and save into a data.frame (called "df") . When I search for it (with the input's and clicking on the button "pesquisa"), a new field called "Grau:" appear for the user, with new selectable values.
How can I update the "df" with the value from the second input? (in that case, the input from the "insertUI" called "Grau:"
---------------- EDITED ------------------------
In my UI code, i have a: DT::dataTableOutput("contents2")
In server side, i have:
output$contents2 = DT::renderDataTable({
tabela_saida})
My first observeEvent is that described above, and save into my df, than, i have a:
tabela_saida = df
The second observeEvent, should update a value called GRAU in my tabela_saida.
The third observEvent, should update AQA...and so on.
The last of all, should expose the datable updated with all the new values and make a search in my database.
I think you want to update your data.frame according to an entry (grau). To do this, you can create an eventReactive that will execute your query. Within eventReactive you need to check if the user has already selected something in input$grau.
This is a way to do this:
library(shiny)
library(DT)
ui <- fluidPage(
mainPanel(
actionButton(inputId = "pesquisa", label = "pesquisa"),
conditionalPanel(condition = "input.pesquisa > 0", uiOutput("grau")),
DT::DTOutput("contents2")
)
)
server <- function(input, output) {
create_df <- eventReactive(input$pesquisa,{
## Your query about here
## ...
##
df <- data.frame(x = round(rnorm(100), 2), grau = rpois(100, lambda = 10))
grau_values <- unique(df$grau)
if(!is.null(input$grau)){
grau_input <- input$grau
df <- subset(df, grau %in% grau_input)
}
return(list(df = df, grau_values = grau_values))
})
output$grau <- renderUI({
grau_values <- create_df()$grau_values
selectInput(inputId = "grau", label = "Grau:", multiple = TRUE, choices = grau_values, selected = NULL)
})
output$contents2 <- DT::renderDataTable({
df <- create_df()$df
datatable(df, rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
I hope it works!
My R program works as expected. It shows a table containing my dataFrame, and lets me edit the values.
How do I capture those values and save them to my dataframe, or a copy of my dataframe?
require(shiny)
library(rhandsontable)
DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = F)
rhandsontable(DF, rowHeaders = NULL)
EDIT:
The above code produces a table with rows and columns. I can edit any of the rows and columns. But when I look at my dataFrame, those edits do not appear. What I am trying to figure out is what do I need to change so I can capture the new values that were edited.
I know this thread's been dead for years, but it's the first StackOverflow result on this problem.
With the help of this post - https://cxbonilla.github.io/2017-03-04-rhot-csv-edit/, I've come up with this:
library(shiny)
library(rhandsontable)
values <- list()
setHot <- function(x)
values[["hot"]] <<- x
DF <- data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = FALSE)
ui <- fluidPage(
rHandsontableOutput("hot"),
br(),
actionButton("saveBtn", "Save changes")
)
server <- function(input, output, session) {
observe({
input$saveBtn # update dataframe file each time the button is pressed
if (!is.null(values[["hot"]])) { # if there's a table input
DF <<- values$hot
}
})
observe({
if (!is.null(input$hot)){
DF <- (hot_to_r(input$hot))
setHot(DF)
}
})
output$hot <- renderRHandsontable({
rhandsontable(DF) %>% # actual rhandsontable object
hot_table(highlightCol = TRUE, highlightRow = TRUE, readOnly = TRUE) %>%
hot_col("big", readOnly = FALSE) %>%
hot_col("small", readOnly = FALSE)
})
}
shinyApp(ui = ui, server = server)
However, I don't like my solution on the part of DF <<- values$hot as I previously had problems with saving changes to the global environment. I've couldn't figure it out any other way, though.
It seems to be accessible now via input$NAME_OF_rHandsontableOutput and can be converted to a data.frame via hot_to_r().
Reproducible example:
library(shiny)
library(rhandsontable)
ui <- fluidPage(
rHandsontableOutput("hottable")
)
server <- function(input, output, session) {
observe({
print(hot_to_r(input$hottable))
})
output$hottable <- renderRHandsontable({
rhandsontable(mtcars)
})
}
shinyApp(ui, server)
I was able to accomplish this with a more simple solution for saving data while the app is open and after it is closed for shiny 1.7++
Create an observe event dependent upon a save button clicked at any point when the app is open. I've scaled this method in more complex apps where you have a selectizeinput for swapping in and out different data frames into the rhandsontable, each of which are edited, saved and recalled while the app is open.
In the server:
observeEvent(input$save, { #button is the name of the save button, change as needed
df <<- hot_to_r(input$rhandsontable) #replace rhandsontable with the name of your own
}) #df is the data frame that have it access when the app starts
In the UI:
actionButton("save","Save Edits")
I don't know what you want to recover exactly, but this seems to work:
DF <- rhandsontable(DF, rowHeaders = NULL)
library(jsonlite)
fromJSON(DF$x$data)
If you are using Shiny then input$table$changes$changes can give you the edited value with row and column index. Below is the code if you want to update only specific cell and not the complete table using hot_to_t().
library(shiny)
library(rhandsontable)
DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = F)
ui <- fluidPage(
rHandsontableOutput('table')
)
server <- function(input, output) {
X = reactiveValues(data = DF)
output$table <- rhandsontable::renderRHandsontable({
rhandsontable(X$data, rowHeaders = NULL)
})
observeEvent(input$table$changes$changes,{
row = input$table$changes$changes[[1]][[1]]
col = input$table$changes$changes[[1]][[2]]
value = input$table$changes$changes[[1]][[4]]
X$data[row,col] = value
})
}
shinyApp(ui, server)
Here's an example from related post How to add columns to a data frame rendered with rhandsontable in R Shiny with an action button?, which started with Tonio Liebrand's solution above but rendered reactively with columns added by the user via action button so you can see the table evolve and see how manual edits to the table stick around:
library(shiny)
library(rhandsontable)
myDF <- data.frame(x = c(1, 2, 3))
ui <- fluidPage(rHandsontableOutput('hottable'),
br(),
actionButton('addCol', 'Add'))
server <- function(input, output, session) {
EmptyTbl <- reactiveVal(myDF)
observeEvent(input$hottable, {
EmptyTbl(hot_to_r(input$hottable))
})
output$hottable <- renderRHandsontable({
rhandsontable(EmptyTbl())
})
observeEvent(input$addCol, {
newCol <- data.frame(c(1, 2, 3))
names(newCol) <- paste("Col", ncol(hot_to_r(input$hottable)) + 1)
EmptyTbl(cbind(EmptyTbl(), newCol))
})
}
shinyApp(ui, server)