How can I put the conditional while rendering the datatable in rshiny - r

I am trying to achieve following steps while working on the rshiny :
1: creating dynamic tabs on click of the cell : DONE
2: creating dynamic subtabs on click of the parent tab : DONE
3: need to render the datatable based on the following condition :
if ( are matching or == ) then display the data accordingly.
please find the below code for your reference :
library(shiny)
library(DT)
library(shinyWidgets)
shinyApp(
ui <- fluidPage(
headerPanel("Product Details"),
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs", id="myTabs",
tabPanel("Company Details", DT::dataTableOutput("data")),
)
)
),
server <- function(input, output, session) {
readXLSXFile <- readxl::read_excel(paste("sample_data.xlsx"),1)
data <- head(readXLSXFile)
tabIndex <- reactiveVal(0)
myValue <- reactiveValues(companyDetails = '')
shinyInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
df <- reactiveValues(data = data.frame(
DealID = data[1],
Details = shinyInput(actionButton, length(data)+1,
'button_', label = "Edit",
onclick = 'Shiny.onInputChange(\"select_button\", this.id)',
style = "color: black;
background-color: white",
class="btn-success",
#icon = icon("edit")
),
Tickers = data[3],
stringsAsFactors = FALSE
# row.names = 1:length(data)
))
output$data <- DT::renderDataTable(
df$data, server = FALSE, escape = FALSE, selection = 'none'
)
observeEvent(input$select_button, {
selectedRow <- as.numeric(strsplit(input$select_button, "_")[[1]][2])
myValue$companyDetails <<- paste('click on ',df$data[selectedRow,1])
stringVal <- c(unlist(strsplit(df$data[selectedRow,3],",")))
topTabValue <- c(df$data[selectedRow,1])
subTabData <- c()
datafromsecondRow <- c(data[2][1])
subTabDataOutput <- c()
data_frame_mod <- c()
appendTab("myTabs",
tabPanel(topTabValue,br(),
actionButton("removeTab", "Remove this Tab", icon = icon("remove")),br(),br(),
tabsetPanel(type="tabs", id=c(topTabValue)
),
),
# select=TRUE
)
lapply(1:length(stringVal), function(i) {
subTabData = stringVal[i]
readXLSXFileSheetTwo <- readxl::read_excel(paste("sample_data.xlsx"),2)
dataFileTwo <- head(readXLSXFileSheetTwo)
# print(c(dataFileTwo$Ticker) %in% c(subTabData))
# print("+++++++++++++++++++")
# print(subTabData)
appendTab(c(topTabValue),
tabPanel(subTabData, br(),
tags$h5(paste("You are at -> ",subTabData)),
output$subTabData <- DT::renderDataTable({
dataFileTwo[c(dataFileTwo$Ticker) %in% c(subTabData),TRUE]
datatable(dataFileTwo, options = list(dom = 'ft'),escape=FALSE)
})
),
# print(c(subTabData))
)
observeEvent(input$subTabData, {
appendTab(subTabData,
tabPanel(topTabValue,br(),
actionButton("removeTab", "Remove this Tab", icon = icon("remove")),br(),br(),
tabsetPanel(type="tabs", id=c(topTabValue)
),
),
)
})
})
})
observeEvent(input$removeTab, {
removeTab("myTabs", target=input$myTabs)
})
output$myText <- renderText({
myValue$companyDetails
})
}
)
Please help me to solve this point.
output$subTabData <- DT::renderDataTable({
**dataFileTwo[c(dataFileTwo$Ticker) %in% c(subTabData),TRUE]**
datatable(dataFileTwo, options = list(dom = 'ft'),escape=FALSE)
})
It is still rendering the whole dataset.. I stuck on conditional render the data on click of subtab.

Related

Register all inputs inside a multi-page data table

I have a datatable in which I've added checkboxes for my users to select various options. Unfortunately, the only inputs that shiny seems to see are ones that have been displayed in the table. So if I have multiple pages, I'm only able to see the first 10 inputs.
In the example below, I've printed all of the inputs that I can see registered above the datatable object. At the moment, I only see the first 10 inputs (A - J). I'd like to be able to see all 26 when the table first loads (without having to toggle through the pages).
In my actual application, I have multiple columns of checkboxes, so row selection wouldn't be sufficient. Any tips or suggestions on how to register all 26 inputs at once?
library(shiny)
library(DT)
shinyInput <- function (FUN, id_base, suffix, label = "", ...)
{
inputId <- paste0(id_base, suffix)
args <- list(...)
args <- c(list(label = label), args)
args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
rv <- character(length(inputId))
for (i in seq_along(rv)) {
this_arg <- lapply(args, `[`, i)
ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
rv[i] <- as.character(ctrl)
}
rv
}
X <- data.frame(id = LETTERS,
selected = sample(c(TRUE, FALSE),
size = length(LETTERS),
replace = TRUE))
X$IsSelected <-
shinyInput(
shiny::checkboxInput,
id_base = "new_input_",
suffix = X$id,
value = X$selected
)
shinyApp(
ui = fluidPage(
verbatimTextOutput("value_check"),
textOutput("input_a_value"),
DT::dataTableOutput("dt")
),
server = shinyServer(function(input, output, session){
Data <- reactiveValues(
X = X
)
output$value_check <-
renderPrint({
sort(names(input))
})
output$dt <-
DT::renderDataTable({
DT::datatable(X,
selection = "none",
escape = FALSE,
filter = "top",
#rownames = FALSE,
class = "compact cell-border",
options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
})
})
)
ADDENDUM
This next example is a bit more complex, but illustrates a bit more of the motivation for the question. It seems the biggest issue is that I would like to utilize buttons such as "select all." Additionally, I'm not processing any actions immediately when a box is interacted with. Instead, the user makes their selections, and the selections are not saved until the "Save Selections" button is clicked.
What is happening is I click on the "Select All" button, and it checks all of the boxes for inputs that have been drawn already. If I've only viewed the first page of the table, it updates only those inputs, and none of the inputs on the next few pages. This is really the behavior I need to change.
# Set up environment ------------------------------------------------
library(shiny)
library(DT)
library(magrittr)
# Example of data coming from the database. -------------------------
set.seed(pi^2)
SourceData <-
data.frame(sample_id = 1:25,
is_selected = sample(c(TRUE, FALSE), 25, replace = TRUE))
# Support Functions -------------------------------------------------
# These would exist, for example, in an internal package
shinyInput <- function (FUN, id_base, suffix, label = "", ...)
{
inputId <- paste0(id_base, suffix)
args <- list(...)
args <- c(list(label = label), args)
args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
rv <- character(length(inputId))
for (i in seq_along(rv)) {
this_arg <- lapply(args, `[`, i)
ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
rv[i] <- as.character(ctrl)
}
rv
}
prepareDataForDisplay <- function(Data){
Data$is_selected <-
shinyInput(shiny::checkboxInput,
id_base = "is_selected_",
suffix = Data$sample_id,
value = Data$is_selected)
Data
}
# User Interface ----------------------------------------------------
ui <-
fluidPage(
verbatimTextOutput("value_check"),
actionButton(inputId = "btn_saveSelection",
label = "Save Selection"),
actionButton(inputId = "btn_selectAll",
label = "Select All"),
actionButton(inputId = "btn_unselectAll",
label = "Unselect All"),
actionButton(inputId = "btn_restoreDefault",
label = "Restore Default (select odd only)"),
DT::dataTableOutput("dt")
)
# Server ------------------------------------------------------------
server <-
shinyServer(function(input, output, session){
# Event Observers -----------------------------------------------
observeEvent(
input$btn_selectAll,
{
check_input <- names(input)[grepl("is_selected_", names(input))]
lapply(check_input,
function(ci){
updateCheckboxInput(session = session,
inputId = ci,
value = TRUE)
})
}
)
observeEvent(
input$btn_unselectAll,
{
check_input <- names(input)[grepl("is_selected_", names(input))]
lapply(check_input,
function(ci){
updateCheckboxInput(session = session,
inputId = ci,
value = FALSE)
})
}
)
observeEvent(
input$btn_restoreDefault,
{
check_input <- names(input)[grepl("is_selected_", names(input))]
lapply(check_input,
function(ci){
id <- as.numeric(sub("is_selected_", "", ci))
updateCheckboxInput(session = session,
inputId = ci,
value = id %% 2 == 1)
})
}
)
observeEvent(
input$btn_saveSelection,
{
check_input <- names(input)[grepl("is_selected_", names(input))]
id <- as.numeric(sub("is_selected_", "", check_input))
for (i in seq_along(check_input)){
SourceData$is_selected[SourceData$sample_id == id[i]] <-
input[[check_input[i]]]
}
# At this point, I would also save changes to the remote database.
DT::replaceData(proxy = dt_proxy,
data = prepareDataForDisplay(SourceData))
}
)
# Output elements -----------------------------------------------
output$value_check <-
renderPrint({
sort(names(input))
})
output$dt <-
DT::renderDataTable({
SourceData %>%
prepareDataForDisplay() %>%
DT::datatable(selection = "none",
escape = FALSE,
filter = "top",
class = "compact cell-border",
options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
})
dt_proxy <- DT::dataTableProxy("dt")
})
# Run the application -----------------------------------------------
shinyApp(
ui = ui,
server = server
)
Here is a workaround based on your addendum (not sure if you need the changes regarding btn_restoreDefault and btn_saveSelection), but the general procedure should be clear:
# Set up environment ------------------------------------------------
library(shiny)
library(DT)
library(magrittr)
# Example of data coming from the database. -------------------------
set.seed(pi^2)
SourceData <-
data.frame(sample_id = 1:25,
is_selected = sample(c(TRUE, FALSE), 25, replace = TRUE))
# Support Functions -------------------------------------------------
# These would exist, for example, in an internal package
shinyInput <- function (FUN, id_base, suffix, label = "", ...)
{
inputId <- paste0(id_base, suffix)
args <- list(...)
args <- c(list(label = label), args)
args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
rv <- character(length(inputId))
for (i in seq_along(rv)) {
this_arg <- lapply(args, `[`, i)
ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
rv[i] <- as.character(ctrl)
}
rv
}
prepareDataForDisplay <- function(Data){
Data$is_selected <-
shinyInput(shiny::checkboxInput,
id_base = "is_selected_",
suffix = Data$sample_id,
value = Data$is_selected)
Data
}
# User Interface ----------------------------------------------------
ui <-
fluidPage(
verbatimTextOutput("value_check"),
actionButton(inputId = "btn_saveSelection",
label = "Save Selection"),
actionButton(inputId = "btn_selectAll",
label = "Select All"),
actionButton(inputId = "btn_unselectAll",
label = "Unselect All"),
actionButton(inputId = "btn_restoreDefault",
label = "Restore Default (select odd only)"),
DT::dataTableOutput("dt")
)
# Server ------------------------------------------------------------
server <-
shinyServer(function(input, output, session){
# Event Observers -----------------------------------------------
observeEvent(
input$btn_selectAll,
{
TmpData <- SourceData
TmpData$is_selected <- TRUE
replaceData(dt_proxy, prepareDataForDisplay(TmpData))
}
)
observeEvent(
input$btn_unselectAll,
{
TmpData <- SourceData
TmpData$is_selected <- FALSE
replaceData(dt_proxy, prepareDataForDisplay(TmpData))
}
)
observeEvent(
input$btn_restoreDefault,
{
replaceData(dt_proxy, prepareDataForDisplay(SourceData))
}
)
observeEvent(
input$btn_saveSelection,
{
check_input <- names(input)[grepl("is_selected_", names(input))]
id <- as.numeric(sub("is_selected_", "", check_input))
TmpData <- SourceData
for (i in seq_along(check_input)){
TmpData$is_selected[TmpData$sample_id == id[i]] <-
input[[check_input[i]]]
}
# At this point, I would also save changes to the remote database.
DT::replaceData(proxy = dt_proxy,
data = prepareDataForDisplay(TmpData))
}
)
# Output elements -----------------------------------------------
output$value_check <-
renderPrint({
sort(names(input))
})
output$dt <-
DT::renderDataTable({
SourceData %>%
prepareDataForDisplay() %>%
DT::datatable(selection = "none",
escape = FALSE,
filter = "top",
class = "compact cell-border",
options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
})
dt_proxy <- DT::dataTableProxy("dt")
})
# Run the application -----------------------------------------------
shinyApp(
ui = ui,
server = server
)

Using two reactives in shiny that depend on each other

I have been trying to create a dashboard with up to 3 inputs and then plot some data. I have done this part but the requirement now has changed that every time there is a selection of a new variable they should also be able to filter the data based on the new input. Here has been my attempt so far:
UI:
library(shiny)
ui <- fluidPage(
sidebarPanel(
tags$br(),
uiOutput("textbox_ui"),
uiOutput("filter_ui"),
tags$br(),
actionButton("add_btn", "Add Factor"),
actionButton("rm_btn", "Remove Factor"),
tags$br(),
actionButton("make","Create Graph and Tables")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Data stuff")
)
)
)
Server:
server <- function(input, output) {
# Track the number of input boxes to render
counter <- reactiveValues(n = 0)
AllInputs <- reactive({
x <- reactiveValuesToList(input)
})
observeEvent(input$add_btn, {
if(counter$n >2){
2
}else{
counter$n <- counter$n + 1
}
})
observeEvent(input$rm_btn, {
if (counter$n > 0) counter$n <- counter$n - 1
})
textboxes <- reactive({
n <- counter$n
if (n > 0) {
isolate({
lapply(seq_len(n), function(i) {
selectInput(inputId = paste0("var", i+1),
label = "",
choices = colnames(mtcars),
selected = AllInputs()[[paste0("var", i+1)]])
})
})
}
})
filterboxes <- reactive({
n <- counter$n
extrainputs <- sapply(seq_len(n), function(i) {
AllInputs()[[paste0("var", i+1)]]
})
summvar <- c(input$var1, extrainputs)
if(n > 0 ){
isolate({
lapply(1:length(summvar), function(x){
text <- summvar[x]
val_level <- unique(mtcars[[text]])
selectInput(inputId = paste0("fil",x+1),
label = paste0("Filter for ", text),
choices = val_level,
multiple = TRUE,
selected = val_level)
})
})
}
})
output$textbox_ui <- renderUI({ textboxes() })
output$filter_ui <- renderUI({ filterboxes() })
}
Two problems arise with this set up so far. One I cannot unselect any of the values when they appear in the filter second I see this warning on the sever side "Warning: Error in .subset2: invalid subscript type 'list'". My reactive skills are quite poor and any suggestions (reactive or not) would be appreciated.
As suggested in my comment...
library(shiny)
myfun <- function(df, var1) {
df %>% mutate(newvar = !!sym(var1)) # create newvar
}
ui <- fluidPage(
sidebarPanel(
tags$br(),
# uiOutput("textbox_ui"),
# uiOutput("filter_ui"),
tags$br(),
tags$div(id = 'placeholder'),
actionButton("add_btn", "Add Factor"),
actionButton("removeBtn", "Remove Factor"),
tags$br(),
actionButton("make","Create Graph and Tables")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Data stuff")
)
)
)
server <- function(input, output, session) {
# Track the number of variables
numvars <- reactiveVal(0)
### keep track of elements/lines inserted and not yet removed
inserted <- c()
observeEvent(input$add_btn, {
if(input$add_btn==0) {
return(NULL)
}
else {
if (numvars()<0) {
numvars(0) # clicking on remove button too many times yields negative number; reset it to zero
}
newValue <- numvars() + 1 # newValue <- rv$numvars + 1
numvars(newValue) # rv$numvars <- newValue
# btn needs to be adjusted if removing and adding factors
if (input$removeBtn==0){
btn <- input$add_btn
}else {
if (input$add_btn > input$removeBtn) {
btn <- input$add_btn - input$removeBtn # add_btn counter does not decrease
}else btn <- numvars()
}
id <- paste0('txt', btn)
insertUI(
selector = '#placeholder',
## wrap element in a div with id for ease of removal
ui = tags$div(
selectInput(inputId = paste0("var", btn),
label = "",
choices = colnames(mtcars)
),
selectInput(inputId = paste0("fil",btn),
label = paste0("Filter for ", id),
choices = "",
multiple = TRUE),
id = id
)
)
}
# inserted <<- c(id, inserted) ## removes first one first
inserted <<- c(inserted, id) ## removes last one first
}, ignoreInit = TRUE) ## end of observeevent for add_btn
observe({
#print(numvars())
lapply(1:numvars(), function(i){
observeEvent(input[[paste0("var",i)]], {
mydf <- mtcars
mydf2 <- myfun(mydf,input[[paste0("var",i)]])
mysub <- unique(mydf2$newvar)
nam <- as.character(input[[paste0("var",i)]])
updateSelectInput(session = session,
inputId = paste0("fil",i),
label = paste0("Filter for ", nam),
choices = mysub,
selected = mysub
)
})
})
})
observeEvent(input$removeBtn, {
newValue <- numvars() - 1
numvars(newValue)
removeUI(
## pass in appropriate div id
selector = paste0('#', inserted[length(inserted)])
)
inserted <<- inserted[-length(inserted)]
print(inserted)
}, ignoreInit = TRUE)
}
shinyApp(ui = ui, server = server)

CheckboxInput with Edit table in DT R Shiny

I tried to combine editing table by adding, deleting row in DT table with checkboxInput(). It is not quite correct.
If I didn't add editing feature, it returned correct, but if I added editing feature,it didn't response after I added another row. I got stuck for a while, I will appreciate any help from you guys
library(shiny)
library(shinyjs)
library(DT)
# Tab 2 UI code.
tab2UI <- function(id) {
ns <- NS(id)
tabPanel(
"Tab 2",
fluidRow(
#uiOutput(ns('cars')),
h2('The mtcars data'),
DT::dataTableOutput(ns('mytable2')),
uiOutput(ns("edit_1")),
h2("Selected"),
tableOutput(ns("checked"))
)
)
}
# Tab 2 server code.
tab2Server <- function(input, output, session) {
ns <- session$ns
# Helper function for making checkboxes.
shinyInput = function(FUN, len, id, ...) {
inputs = character(len)
for (i in seq_len(len)) {
inputs[i] = as.character(FUN(ns(paste0(id, i)), label = NULL, ...))
}
inputs
}
# Update table records with selection.
subsetData <- reactive({
sel <- mtcars[1:5,]
})
values <- reactiveValues(df = NULL)
observe({
values$df <- subsetData()
})
# Datatable with checkboxes.
output$mytable2 <- DT::renderDataTable(
datatable(
data.frame(values$df,Favorite=shinyInput(checkboxInput,nrow(values$df), "cbox_", width = 10)),
editable = TRUE,
selection = 'single',
escape = FALSE,
options = list(
paging = FALSE,
preDrawCallback = JS('function() {Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() {Shiny.bindAll(this.api().table().node()); }')
)
)
)
observeEvent(input$add.row_1,{
# print(paste0("Row selected",input$mytable2_rows_selected))
if (!is.null(input$mytable2_rows_selected)) {
td <- values$df
tid_n = as.numeric(input$mytable2_rows_selected)
tid = as.numeric(input$mytable2_rows_selected) + 1
if(tid_n == nrow(td)){
td<- rbind(data.frame(td[1:tid_n, ]),
data.frame(td[tid_n, ]))
}else{
td<- rbind(data.frame(td[1:tid_n, ]),
data.frame(td[tid_n, ]),
data.frame(td[tid: nrow(td), ]))
}
td <- data.frame(td)
print(td)
values$df <- td
}
})
output$edit_1 <- renderUI({
tagList(
actionButton(inputId = ns("add.row_1"), label = "Add Row", icon = icon("plus"),class = "example-css-selector",style = "background-color:gray; border-color:gray;color:white;height:31px;"),
actionButton(inputId = ns("delete.row_1"), label = "Delete Row", icon = icon("minus"),class = "example-css-selector",style = "background-color:gray; border-color:gray;color:white;height:31px;"),br(),br()
)
})
# Helper function for reading checkbox.
shinyValue = function(id, len) {
values <- unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) NA else value
}))
return(values)
}
# Output read checkboxes.
observe({
len <- nrow(values$df)
output$checked <- renderTable({
data.frame(selected=shinyValue("cbox_", len))
})
})
}
# Define UI for application.
ui <- fluidPage(
useShinyjs(),
navbarPage(
'Title',
tab2UI("tab2")
)
)
# Define server.
server <- function(input, output, session) {
# Call tab2 server code.
callModule(tab2Server, "tab2")
}
# Run the application
shinyApp(ui = ui, server = server)

Is there a way to select or return the selected variable from dropdown in selected via selectInput?

I am trying to build a function which will select the data variables entered from the file and show the data variables to be selected via the dropdown and to display the variable that is selected currently.
Here, I am able to add file and show the variables of data in the dropdown in the Filter Tab, however I am unable to catch the currently selected variable in the server to apply filter.
Below is the code
server.R
library(shiny)
library(shinyBS)
library(shinyjs)
server <- function(input, output, session) {
myValue <- reactiveValues()
# Import Data File
observeEvent(input$data_import,{
if(is.null(input$datafile))
myValue$data<-NULL
inFile<-input$datafile
myValue$data <- rio::import(inFile$datapath)
})
# Render Input DataTable
output$show_data <- DT::renderDataTable(
myValue$data, server = FALSE, escape = FALSE, selection = 'none'
)
#Functions
shinyInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
SingleshinyInput <- function(FUN, i, id, ...) {
inputs <- character(i)
inputs <- as.character(FUN(paste0(id, i), ...))
inputs
}
#Display Dynamic Input Filter table
observe({
if(is.null(myValue$data))
return()
Names <- colnames(myValue$data)
myValue$Filter = data.frame(
Logic = c(NA,shinyInput(selectInput, 4, 'logic_', label = "", choices = c("And","Or"))),
Variable = shinyInput(selectInput, 5, 'var_', label = "", choices = Names ),
Filter = shinyInput(actionButton, 5, 'go_button_', label = "Filter", onclick = 'Shiny.onInputChange(\"select_button\", this.id)' ),
Remove = shinyInput(actionButton, 5, 'remove_button_', "", icon = icon("close"), onclick = 'Shiny.onInputChange(\"select_remove_button\", this.id)' ),
stringsAsFactors = FALSE,
row.names = 1:5
)
}
)
#Add new Filter Row
observeEvent(input$addnewRow,{
if(is.null(myValue$Filter))
return()
i <- as.character(max(as.numeric(row.names(myValue$Filter)))+1)
newRow <- data.frame(Logic = SingleshinyInput(selectInput, i, 'logic_', label = "", choices = c("And","Or")),
Variable = SingleshinyInput(selectInput, i, 'var_', label = "", choices = Names ),
Filter = SingleshinyInput(actionButton, i, 'go_button_', label = "Filter", onclick = 'Shiny.onInputChange(\"select_button\", this.id)' ),
Remove = SingleshinyInput(actionButton, i, 'remove_button_', "", icon = icon("close"), onclick = 'Shiny.onInputChange(\"select_remove_button\", this.id)' ),
stringsAsFactors = FALSE,
row.names = i)
myValue$Filter <- rbind(myValue$Filter,newRow)
})
# Render Filter Data Table
output$data <- DT::renderDataTable(
myValue$Filter, server = FALSE, escape = FALSE, selection = 'none'
)
# Remove filter Row
observeEvent(input$select_remove_button,{
if(is.null(myValue$Filter))
return()
rowToRemove<-unlist(strsplit(input$select_remove_button,"_"))
rowToRemove<-rowToRemove[length(rowToRemove)]
rowToRemove<-which(row.names(myValue$Filter)==rowToRemove)
myValue$Filter<-myValue$Filter[-rowToRemove,]
if(!is.na(myValue$Filter$Logic[1]))
myValue$Filter$Logic[1]<-NA
})
# Display bsModal for filter
observeEvent(input$select_button, {
toggleModal(session,"CustomDataFilter",toggle="open")
})
# Select the variable value selected in the select Input
output$FilterDataSettings <- renderUI({
selected<-unlist(strsplit(input$select_button,"_"))
selected<-as.numeric(selected[length(selected)])
Names <- colnames(myValue$data)
selected_var<-Names[selected]
print(selected_var)
selected<-as.numeric(selected)
print(input[[paste0("var_",selected)]])
return(NULL)
})
output$result <- renderText({
selected<-unlist(strsplit(input$select_button,"_"))
selected<-as.numeric(selected[length(selected)])
paste("You chose", input[[paste0("var_",selected)]])
print(input[[paste0("var_",selected)]])
})
# Show Table Dimensions
output$showDataDimensions.FilterData <- renderUI({
if(is.null(myValue$data)){
return(paste("The data is not selected "))
}
Dim<-dim(myValue$data)
paste("Dimensions", Dim[1], "X" , Dim[2])
})
}
ui.r
shinyUI(fluidPage(
tags$button(
id = "reset_button",
class="btn action-button",
icon("close")
),
bsModal("CustomDataFilter","Settings","go_CustomDataFilter_Settings",size="small",
# radioButtons("Less_Than_Greater_Than","Less Than or Greater Than",choices=c("Less Than","Greater Than"),selected="Less Than",inline = TRUE),
uiOutput("FilterDataSettings"),
textOutput("result")
),
tabsetPanel(
tabPanel("Data",
titlePanel("Custom Data Filter"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', h4('Import File'),
accept=c('text/csv', 'text/comma-separated-values,text/plain')),
actionButton("data_import","Import")
),
mainPanel(
DT::dataTableOutput("show_data")
)
)
),
tabPanel("Filter",
sidebarLayout(
sidebarPanel(
uiOutput("showDataDimensions.FilterData")
),
mainPanel(
DT::dataTableOutput("data"),
actionButton("addnewRow"," Add New Filter "),
actionButton("applyFilter"," Apply Filter to Data ")
)
)
)
)
)
)
Thank you for going through the code and appreciate your response.

User input in DataTable used for recalculation and update of column in Shiny

I want to create a web app, which allows user to enter input in numericInput object, which is embedded in DataTable and recalculates result (multiplication of column with some static values and a user input column) in another column.
I believe that when I set a reactive function which wraps around merging dataset and user input column and later I call it from RenderDataTable, that I somehow break the reactivity and I don't have a clue how to keep reactivity within table dependent on user input (which is also in the table). Please help.
Reproducible example to where I am stuck:
library(shiny)
library(DT)
set.seed(21)
db <- data.frame(ent = rep(x = 1,5),
group = c("G","M","O","F","L"),
val = sample(1:100, 5, replace=TRUE))
ui <- fluidPage(
titlePanel(paste0("entity - ", unique(db$ent))),
sidebarLayout(
sidebarPanel(
helpText("Shiny app calculation")
),
mainPanel(
DT::dataTableOutput("table")
))
)
numericText <- function(FUN, id_nums, id_base, label, value, ...) {
inputs <- 1:length(id_nums)
for (i in 1:length(inputs)) {
inputs[i] <- as.character(FUN(paste0(id_base,
id_nums[i]), label, value, ...))
}
return(inputs)
}
inputs <- numericText(numericInput,
id_nums = as.character(1:5),
id_base = "input_",
label = NULL,
value = 0)
db <- data.frame(db,
num = inputs)
server <- function(input, output, session) {
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) NA else value
}))
}
output_table <- reactive({
data.frame(db, calc = shinyValue("input_", 5))
})
output$table <- renderDataTable({
datatable(output_table(), rownames = FALSE, escape = FALSE, selection
= 'none', options = list(paging = FALSE, ordering = FALSE, searching
= FALSE, preDrawCallback = JS('function() {
Shiny.unbindAll(this.api().table().node()); }'), drawCallback =
JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
})
}
shinyApp(ui = ui, server = server)
Also maybe it helps - I was able to do this if I remove reactive expression from the dataframe and if I write result in another output type(however this is not a solution, since my main purpose is to write it in another column in DataTable):
library(shiny)
library(DT)
set.seed(21)
db <- data.frame(ent = rep(x = 1,5),
group = c("G","M","O","F","L"),
val = sample(1:100, 5, replace=TRUE))
ui <- fluidPage(
titlePanel(paste0("entity - ", unique(db$ent))),
sidebarLayout(
sidebarPanel(
helpText("Shiny app calculation")
),
mainPanel(
DT::dataTableOutput("table"),
verbatimTextOutput("text")
))
)
numericText <- function(FUN, id_nums, id_base, label, value, ...) {
inputs <- 1:length(id_nums)
for (i in 1:length(inputs)) {
inputs[i] <- as.character(FUN(paste0(id_base,
id_nums[i]), label, value, ...))
}
return(inputs)
}
inputs <- numericText(numericInput,
id_nums = as.character(1:5),
id_base = "input_",
label = NULL,
value = 0)
db <- data.frame(db,
num = inputs)
server <- function(input, output, session) {
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) NA else value
}))
}
output_table <- db
output$table <- renderDataTable({
datatable(output_table, rownames = FALSE, escape = FALSE, selection
= 'none', options = list(paging = FALSE, ordering = FALSE, searching
= FALSE, preDrawCallback = JS('function() {
Shiny.unbindAll(this.api().table().node()); }'), drawCallback =
JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
})
}
output$text <- reactive({shinyValue("input_", 5) * db$val
})
shinyApp(ui = ui, server = server)
I couldn't fully understand your code so I've myself produced another reproducible example based on a bunch of other answers especially this one.
library(shiny)
library(data.table)
library(rhandsontable)
DF = data.frame(num = 1:10, qty = rep(0,10), total = 1:10,
stringsAsFactors = FALSE)
#DF = rbind(DF, c(0,0,0))
ui = fluidPage(
titlePanel("Reactive Table "),
fluidRow(box(rHandsontableOutput("table", height = 400)))
)
server = function(input, output) {
data <- reactiveValues(df=DF)
observe({
input$recalc
data$df <- as.data.frame(DF)
})
observe({
if(!is.null(input$table))
data$df <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
rhandsontable(data$df)
})
output$table <- renderRHandsontable({
data$df$total <- data$df$num * data$df$qty
print(sum(data$df$num*data$df$price) )
rhandsontable(data$df, selectCallback = TRUE)
})
}
shinyApp(ui, server)
The very first idea is to use rhandsontable which is specifically for this kind of purpose.

Resources