Add row number column to a reactive data frame in Shiny - r

I am trying to add a row index column to a reactive data frame created on-the-fly from user inputs. I am able to do this outside of Shiny using the tibble::rowid_to_column function but cannot make it work in the below Shiny app (line 44). Can someone please provide guidance on how to make it work? Also, when I delete a row from the data frame, how can we make rowid numbers sequential again? Thanks.
library(shiny)
library(DT)
library(tidyverse)
input_data <- data.frame(
# rowid = double(),
input1 = character(),
input2 = double(),
stringsAsFactors = FALSE)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
selectInput("input1",
"Input 1",
choices = c("Value 1", "Value 2", "Value 3")),
numericInput("input2",
"Input 2",
value = 100),
actionButton("add_btn",
"Add Row"),
actionButton("delete_btn",
"Delete Row"),
actionButton("reset_btn",
"Reset"),
position = "left"
),
mainPanel(
DT::dataTableOutput("input_table")
)
)
)
server <- function(input, output) {
input_table <- reactiveVal(input_data)
observeEvent(input$add_btn, {
t = rbind(input_table(), data.frame(col1 = input$input1, col2 = input$input2))
# %>%
# cbind(tibble::rowid_to_column("rowid"))
input_table(t)
})
observeEvent(input$delete_btn, {
t = input_table()
print(input$input_table_rows_selected)
if (!is.null(input$input_table_rows_selected)) {
t <- t[-input$input_table_rows_selected,]
}
input_table(t)
})
observeEvent(input$reset_btn, {
input_table(input_data)
})
output$input_table <- DT::renderDataTable({
datatable(input_table())
})
}
shinyApp(ui = ui, server = server)

rowid_to_column() adds the row names of a tibble and adds them as a column to the data frame. This won't work for you: once you have added the rownames in a column rowid, you cannot add that column a second time. Also, the function returns the entire tibble with the new column added, so it makes no sense to cbind() the output of rowid_to_column() it to the tibble.
I suggest the following changes to your code:
Define the initial Table with the rowid column:
input_data <- tibble(
rowid = integer(),
input1 = character(),
input2 = double()
)
In the first observer, change the code to this:
observeEvent(input$add_btn, {
new_row <- tibble(rowid = nrow(input_table()) + 1,
input1 = input$input1,
input2 = input$input2)
t = bind_rows(input_table(), new_row)
input_table(t)
})
This creates a new row with the appropriate rowid and then adds it to the table.
In order to have the expected rowids after deletion of a row you simply have to redefine the rowids each time a row is delted:
observeEvent(input$delete_btn, {
t <- input_table()
print(input$input_table_rows_selected)
if (!is.null(input$input_table_rows_selected)) {
t <- t[-input$input_table_rows_selected, ]
# reset the rowids only, when there is at least one row left
if (nrow(t) > 0) {
t$rowid <- 1:nrow(t)
}
}
input_table(t)
})
And when rendering the output table, you have to suppress the row names:
output$input_table <- DT::renderDataTable({
datatable(input_table(), rownames = FALSE)
})

Related

How to break dependence between tables dynamically rendered in R Shiny App?

In the below code, I took one of the examples from https://community.rstudio.com/t/shiny-app-with-dynamic-number-of-datatables/2405/4 for dynamically adding tables. The example used tables rendered with DT and I made minor modifications to use it for rhandsontable.
However, I'm having trouble making the tables independent of one another. When adding a new table, it should be "seeded" with the default values per dataframe data1 and its related rowNames1, but thereafter they should be independent as illustrated below. I'm fairly sure the solution has something to do with creating a dynamic equivalent of the reactive uiTable1 used in the code for holding table values, but I don't know how to do this.
Any ideas for accomplishing this?
Inputs into the base (master) and added tables will be used elsewhere in the full code this is intended for.
Code:
library(rhandsontable)
library(shiny)
rowNames1 <- c('A','B','C','Sum')
data1 <- data.frame(row.names = rowNames1, 'Col 1' = c(1,1,0,2), check.names = FALSE)
ui <- fluidPage(
rHandsontableOutput('hottable1'), # undeletable base table
actionButton("addTbl", "Add table"), # adds new table
tags$div(id = "placeholder")
)
server <- function(input, output) {
uiTable1 <- reactiveVal(data1) # undeletable base table
rv <- reactiveValues() # used for dynamic table add/removal
# records changes to base table and will need same for added tables:
observeEvent(input$hottable1,{uiTable1(hot_to_r(input$hottable1))})
output$hottable1 <- renderRHandsontable({
rhandsontable(uiTable1(),rowHeaderWidth = 100, useTypes = TRUE)
})
# adds column summation to last row of table, will need for all added tables too:
observe({
req(input$hottable1)
DF <- hot_to_r(input$hottable1)
DF[setdiff(rowNames1, "Sum"),]
DF["Sum",] <- colSums(DF[setdiff(rowNames1, "Sum"),, drop = FALSE], na.rm = TRUE)
uiTable1(DF)
})
# dynamically add/remove tables:
observeEvent(input$addTbl, {
divID <- gsub("\\.", "", format(Sys.time(), "%H%M%OS3"))
dtID <- paste0(divID, "DT")
btnID <- paste0(divID, "rmv")
insertUI(
selector = "#placeholder",
ui = tags$div(id = divID,
actionButton(btnID, "Remove table", class = "pull-left btn btn-danger"),
rHandsontableOutput(dtID),
hr()
)
)
output[[dtID]] <- renderRHandsontable({
rhandsontable(uiTable1(),rowHeaderWidth = 100, useTypes = TRUE)
})
# remove table from the app when remove button clicked
observeEvent(input[[btnID]], {
removeUI(selector = paste0("#", divID))
rv[[divID]] <- NULL
}, ignoreInit = TRUE, once = TRUE)
})
}
shinyApp(ui,server)
We can use reactiveValues to store the information of each new table. These tables will start with the values of the base table available at that time. Afterwards they will stop reacting to changes inside the main table.
First we create the base table uiTable1 <- reactiveValues(table_base = data1) # undeletable base table
And finally all the subsequent tables will be created as uiTable1[[glue("{divID}table")]] <- uiTable$table_base
library(rhandsontable)
library(shiny)
library(glue)
rowNames1 <- c("A", "B", "C", "Sum")
data1 <- data.frame(row.names = rowNames1, "Col 1" = c(1, 1, 0, 2), check.names = FALSE)
ui <- fluidPage(
rHandsontableOutput("hottable1"), # undeletable base table
actionButton("addTbl", "Add table"), # adds new table
tags$div(id = "placeholder")
)
server <- function(input, output) {
uiTable1 <- reactiveValues(table_base = data1) # undeletable base table
rv <- reactiveValues() # used for dynamic table add/removal
# records changes to base table and will need same for added tables:
observeEvent(input$hottable1, {
uiTable1$table_base <- hot_to_r(input$hottable1)
})
output$hottable1 <- renderRHandsontable({
rhandsontable(uiTable1$table_base, rowHeaderWidth = 100, useTypes = TRUE)
})
# adds column summation to last row of table, will need for all added tables too:
observe({
req(input$hottable1)
DF <- hot_to_r(input$hottable1)
DF[setdiff(rowNames1, "Sum"), ]
DF["Sum", ] <- colSums(DF[setdiff(rowNames1, "Sum"), , drop = FALSE], na.rm = TRUE)
uiTable1$table_base <- DF
})
# dynamically add/remove tables:
observeEvent(input$addTbl, {
divID <- gsub("\\.", "", format(Sys.time(), "%H%M%OS3"))
dtID <- paste0(divID, "DT")
btnID <- paste0(divID, "rmv")
# capture the current state of the main table
uiTable1[[glue("{divID}table")]] <- uiTable1$table_base
insertUI(
selector = "#placeholder",
ui = tags$div(
id = divID,
actionButton(btnID, "Remove table", class = "pull-left btn btn-danger"),
rHandsontableOutput(dtID),
hr()
)
)
output[[dtID]] <- renderRHandsontable({
req(uiTable1[[glue("{divID}table")]])
rhandsontable(uiTable1[[glue("{divID}table")]], rowHeaderWidth = 100, useTypes = TRUE)
})
# adds column summation to last row of table, will need for all added tables too:
observeEvent(input[[dtID]], {
DF <- hot_to_r(input[[dtID]])
DF[setdiff(rowNames1, "Sum"), ]
DF["Sum", ] <- colSums(DF[setdiff(rowNames1, "Sum"), , drop = FALSE], na.rm = TRUE)
uiTable1[[glue("{divID}table")]] <- DF # update the table with the sum
})
# remove table from the app when remove button clicked
observeEvent(input[[btnID]],
{
removeUI(selector = paste0("#", divID))
rv[[divID]] <- NULL
uiTable1[[glue("{divID}table")]] <- NULL
},
ignoreInit = TRUE,
once = TRUE
)
})
}
shinyApp(ui, server)

how to make a copy of reactive table in R shiny in `reactiveValues()`

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.

Update a tibble and a dropdown when a button is clicked; update the tibble when choices are made in the dropdown

I've created the Shiny app below:
library(shiny)
library(shinyWidgets)
library(tidyverse)
tbl1 <- tibble(obs = as_factor(letters[1:3]), val = -1:1)
tbl2 <- tibble(obs = as_factor(letters[1:3]), val = 0:2)
flag_outliers <- function(tbl) {
tbl %>% mutate(is_outlier = near(val, min(val)) | near(val, max(val)))
}
ui <- fluidPage(
column(6,
radioButtons("tbl", "Select tibble", choices = c("tbl1", "tbl2")),
actionButton("flag_w_func", "Flag outliers with function"),
pickerInput(
"user_choices", "Flag outliers yourself",
letters[1:3], multiple = TRUE, options = pickerOptions(actionsBox = TRUE)
)
),
column(6, tableOutput("tbl_w_flags"))
)
server <- function(input, output, session) {
tbl <- reactive(switch(input$tbl, tbl1 = tbl1, tbl2 = tbl2))
tbl_w_flags <- reactive(flag_outliers(tbl())) # Not sure what this should be
output$tbl_w_flags <- renderTable(tbl_w_flags())
}
shinyApp(ui, server)
This defines two tibbles, tbl1 and tbl2, and allows the user to choose one; their choice is stored in tbl in the server function. I want to create another tibble in the server function called tbl_w_flags that's tbl plus an is_outlier column.
If the user clicks on the "Flag outliers with function" button, the is_outlier column should be set using flag_outliers(). Also, the dropdown list user_choices should display check marks next to the observations that have been flagged by flag_outliers() and those observations only.
If the user checks or unchecks observations in the dropdown list, the is_outlier column should be updated appropriately - the appropriate values should be changed to TRUE or FALSE.
Thus, tbl_w_flags needs to be modified if the button is clicked or choices are made in the dropdown list, and the dropdown list needs to be modified if the button is clicked.
I don't have much Shiny experience and am struggling to figure out how to do this. Is this possible? If so, how can it be accomplished?
I removed tbl_w_flags and directly updated tbl(), two reactive are not necessary here. I also used reactiveVal for reactive and added an updatePickerInput to also update the picker if the button is clicked
library(shiny)
library(shinyWidgets)
library(tidyverse)
tbl1 <- tibble(obs = as_factor(letters[1:3]), val = -1:1)
tbl2 <- tibble(obs = as_factor(letters[1:3]), val = 0:2)
flag_outliers <- function(tbl) {
tbl %>% mutate(is_outlier = near(val, min(val)) | near(val, max(val)))
}
ui <- fluidPage(
column(6,
radioButtons("tbl", "Select tibble", choices = c("tbl1", "tbl2")),
actionButton("flag_w_func", "Flag outliers with function"),
pickerInput(
"user_choices", "Flag outliers yourself",
letters[1:3], multiple = TRUE, options = pickerOptions(actionsBox = TRUE)
)
),
column(6, tableOutput("tbl_w_flags"))
)
server <- function(input, output, session) {
tbl <- reactiveVal()
observe(tbl(switch(input$tbl, tbl1 = tbl1, tbl2 = tbl2)))
observe(input$user_choices)
observeEvent(input$flag_w_func, {
old_tbl <- tbl()
new_tbl <- flag_outliers(old_tbl)
# Update reactive tbl and user_choice pickerInput
tbl(new_tbl)
new_choices <- new_tbl %>% filter(is_outlier) %>% pull(obs)
updatePickerInput(session, "user_choices", selected = new_choices)
})
observeEvent(input$user_choices, {
old_tbl <- tbl()
new_tbl <- old_tbl %>% mutate(is_outlier = c(obs %in% input$user_choices))
# Update reactive tbl()
tbl(new_tbl)
})
output$tbl_w_flags <- renderTable(tbl())
}
shinyApp(ui, server)
Edit:
If you like to reset the picker whenever the tibble is changed (using the radio buttons), change your first observer to
observe({
tbl(switch(input$tbl, tbl1 = tbl1, tbl2 = tbl2))
updatePickerInput(session, "user_choices", selected = character(0))
})

Update reactiveValues in Shiny R

I understand similar questions have been asked and I've tried virtually every solution with no luck.
In my application, I've allowed the user to modify individual cells of a DT::datatable. The source of the datatable is a reactive data frame.
After the user makes changes to the clientside datatable, the datatable source is remains unchanged. This is an issue as later on, when I allow the user to add rows to the data table, the row is added onto the source datatable where the clientside datatable then reflects this change. However, this means that if the user makes a change to a cell in the clientside datatable, when the user adds a row to the same table, the change made by the user will be forgotten as it was never made to the source.
I've tried many ways to update the underlying/serverside datatable with no luck. editData keeps giving me errors/NA. I also have tried indexing the serverside table and placing the changed value inside of it, with no luck. I'll post my code below with some comments for specifics..
library(shiny)
library(DT)
library(data.table)
source('~/camo/camo/R/settings.R')
source('~/camo/camo/etl.R')
# Define UI ----
ui <- fluidPage(
titlePanel("PAlpha"),
mainPanel(
fluidRow(
tabsetPanel(id = 'tpanel',
type = "tabs",
tabPanel("Alpha", plotOutput("plot1")),
tabPanel("Beta", plotOutput("plot2")),
tabPanel("Charlie", plotOutput("plot3")),
tabPanel("Delta", plotOutput("plot4")))
),
fluidRow(
splitLayout(
dateInput("sdate", "Start Date"),
dateInput("edate", "End Date"),
textInput("gmin", "Global Minimum"),
textInput("gmax", "Global Maximum")
)
),
fluidRow(
splitLayout(
textInput("groupInp", NULL, placeholder = "New Group"),
actionButton("addGrpBtn", "Add Group"),
textInput("tickerInp", NULL, placeholder = "New Ticker"),
actionButton("addTickerBtn", "Add Ticker")
)
),
fluidRow(
splitLayout(
DT::dataTableOutput('groupsTable'),
DT::dataTableOutput('groupTickers')
),
verbatimTextOutput("print")
)
)
)
# Define server logic ----
server <- function(input, output) {
port_proxy <- dataTableProxy('groupsTable')
rv <- reactiveValues(
portfolio = data.frame('Group' = c('Portfolio'), 'Minimum Weight' = c(0), 'Maximum Weight' = c(0), 'Type' = c('-')),
groups = list(group1 = data.frame('Group' = c('Ticker'), 'Minimum Weight' = c(0), 'Maximum Weight' = c(0), 'Type' = c('-'))),
deletedRows = NULL,
deletedRowIndices = list()
)
output$groupsTable <- DT::renderDataTable(
# Add the delete button column
deleteButtonColumn(rv$portfolio, 'delete_button')
)
output$print <- renderPrint({
rv$portfolio
})
############## LISTENERS ################
observeEvent(input$deletePressed, {
rowNum <- parseDeleteEvent(input$deletePressed)
dataRow <- rv$portfolio[rowNum,]
# Put the deleted row into a data frame so we can undo
# Last item deleted is in position 1
rv$deletedRows <- rbind(dataRow, rv$deletedRows)
rv$deletedRowIndices <- append(rv$deletedRowIndices, rowNum, after = 0)
# Delete the row from the data frame
rv$portfolio <- rv$portfolio[-rowNum,]
})
observeEvent(input$addGrpBtn, {
row <- data.frame('Group' = c(input$groupInp),
'Minimum Weight' = c(0),
'Maximum Weight' = c(0),
'Type' = c('-'))
rv$portfolio <- addRowAt(rv$portfolio, row, nrow(rv$portfolio))
})
observeEvent(input$groupsTable_cell_edit,{
info <- str(input$groupsTable_cell_edit)
i <- info$row
j <- info$col
v <- info$value
rv$portfolio <- editData(rv$portfolio, input$groupsTable_cell_edit) # doesn't work see below
# Warning in DT::coerceValue(v, data[i, j, drop = TRUE]) :
# New value(s) "test" not in the original factor levels: "Portfolio"; will be coerced to NA.
# rv$portfolio[i,j] <- input$groupsTable_cell_edit$value
# rv$portfolio[i,j] <- v #doesn't work
})
}
addRowAt <- function(df, row, i) {
# Slow but easy to understand
if (i > 1) {
rbind(df[1:(i - 1), ], row, df[-(1:(i - 1)), ])
} else {
rbind(row, df)
}
}
deleteButtonColumn <- function(df, id, ...) {
# function to create one action button as string
f <- function(i) {
# https://shiny.rstudio.com/articles/communicating-with-js.html
as.character(actionLink(paste(id, i, sep="_"), label = 'Delete', icon = icon('trash'),
onclick = 'Shiny.setInputValue(\"deletePressed\", this.id, {priority: "event"})'))
}
deleteCol <- unlist(lapply(seq_len(nrow(df)), f))
# Return a data table
DT::datatable(cbind(' ' = deleteCol, df),
# Need to disable escaping for html as string to work
escape = FALSE,
editable = 'cell',
selection = 'single',
rownames = FALSE,
class = 'compact',
options = list(
# Disable sorting for the delete column
dom = 't',
columnDefs = list(list(targets = 1, sortable = FALSE))
))
}
parseDeleteEvent <- function(idstr) {
res <- as.integer(sub(".*_([0-9]+)", "\\1", idstr))
if (! is.na(res)) res
}
# Run the app ----
shinyApp(ui = ui, server = server)
As far as I have looked, there is no ready-to-go solution available. You could try to use rhandsontable. It does not provide all the functionality of the DT table, however it allows for the editing. Last time I tried using it there were some minor issues in some edge cases. (Trying to save different data type or something similar.)
Alternatively you can do the stuff manually, along these lines. This is the minimal working example of editing the underlying data frame. Currently I overwrite it every time the user clicks on the table, you would need to change that to handle normal user behavior. It is meant merely as a proof of concept.
library(DT)
library(shiny)
ui <- fluidPage(
DT::dataTableOutput("test")
)
myDF <- iris[1:10,]
js <- c("table.on('click.dt','tr', function() {",
" var a = table.data();",
" var data = []",
" for (i=0; i!=a.length; i++) {",
" data = data.concat(a[i]) ",
" };",
"Shiny.setInputValue('dataChange', data)",
"})")
server <- function(input, output) {
output$test <- DT::renderDataTable(
myDF,
editable='cell',
callback=JS(js)
)
observeEvent(input$dataChange, {
res <- cbind.data.frame(split(input$dataChange, rep(1:6, times=length(input$dataChange)/6)),
stringsAsFactors=F)
colNumbers <- res[,1]
res <- res[,2:ncol(res)]
colnames(res) <- colnames(myDF)
myDF <<- res
print(myDF)
})
}
shinyApp(ui = ui, server = server)

Updating a data.frame with an observeEvent

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!

Resources