Reputation: 613
I have some code to program a small shiny app for which I need to add input rows and, if needed, delete them again. I have figured out how to add inputs, however I can't figure out how to delete them.
Here is a MWE of my code. There is no output since I cannot share the excel sheet behind the code from which the output is generated. However, it should suffice for simply helping me find the correct code to remove the added rows with full input (except the first row):
library(shiny)
GeographyList <- c("Africa","Asia Pacific","Europe","Global", "United States","Latin America & Caribbean")
RegionList <- c("Emerging",
"Developed")
ClassList <- c("1",
"2",
"3")
# Define UI for app that draws a plot ----
ui <- fluidPage(
fluidRow(
mainPanel(
uiOutput("inputwidgets"),
actionButton("number",
"Add Row"),
# Input: Click to update the Output
actionButton("update", "Update View"),
# Output: Plot ----
h4("Allocation"),
plotOutput("distPlot")
)
)
)
# Define server logic required to call the functions required ----
server <- function(input, output, session) {
# Get new input by clicking Add Row
observeEvent(input$number, {
output$inputwidgets = renderUI({
input_list <- lapply(1:input$number, function(i) {
# for each dynamically generated input, give a different name
fluidRow(
column(2,
selectInput(paste0("Geography", i),
label = paste0("Geography", i),
choices = GeographyList,
multiple = FALSE,
selected = NA)
),
column(3,
selectInput(paste0("Region", i),
label = paste0("Region", i),
choices = RegionList,
multiple = FALSE,
selected = NA)
),
column(4,
selectInput(paste0("Class", i),
label = paste0("Class", i),
choices = ClassList,
multiple = FALSE,
selected = NA)
),
column(3,
# Input: Specify the amount ----
numericInput(paste0("amount",i), label="Amount", 0)
))
})
do.call(tagList, input_list)
})
})
output$distPlot <- renderPlot({
if (input$update == 0)
return()
isolate(input$number)
isolate(input$amount)
slices <- c(input$amount1,input$amount2,input$amount3,input$amount4)
pie(slices)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
Appreciate any tips since I am very new to shiny! Thanks in advance.
Upvotes: 0
Views: 41
Reputation: 1302
You could build your lapply
loop based on a reactiveValue which is triggered by your add button and a delete button:
1. Edit: using sapply
in output$distPlot
according to lapply
rows
2. Edit: using existing input values
library(shiny)
GeographyList <- c("Africa","Asia Pacific","Europe","Global", "United States","Latin America & Caribbean")
RegionList <- c("Emerging",
"Developed")
ClassList <- c("1",
"2",
"3")
# Define UI for app that draws a plot ----
ui <- fluidPage(
fluidRow(
mainPanel(
uiOutput("inputwidgets"),
actionButton("number",
"Add Row"),
actionButton("delete_number",
"Delete Row"),
# Input: Click to update the Output
actionButton("update", "Update View"),
# Output: Plot ----
h4("Allocation"),
plotOutput("distPlot")
)
)
)
# Define server logic required to call the functions required ----
server <- function(input, output, session) {
reac <- reactiveValues()
observeEvent(c(input$number,input$delete_number), {
# you need to add 1 to not start with 0
add <- input$number+1
# restriction for delete_number > number
delete <- if(input$delete_number > input$number) add else input$delete_number
calc <- add - delete
reac$calc <- if(calc > 0) 1:calc else 1
})
# Get new input by clicking Add Row
observe({
req(reac$calc)
output$inputwidgets = renderUI({
input_list <- lapply(reac$calc, function(i) {
Geography <- input[[paste0("Geography",i)]]
Region <- input[[paste0("Region",i)]]
Class <- input[[paste0("Class",i)]]
amount <- input[[paste0("amount",i)]]
# for each dynamically generated input, give a different name
fluidRow(
column(2,
selectInput(paste0("Geography", i),
label = paste0("Geography", i),
choices = GeographyList,
multiple = FALSE,
selected = if(!is.null(Geography)) Geography
)
),
column(3,
selectInput(paste0("Region", i),
label = paste0("Region", i),
choices = RegionList,
multiple = FALSE,
selected = if(!is.null(Region)) Region
)
),
column(4,
selectInput(paste0("Class", i),
label = paste0("Class", i),
choices = ClassList,
multiple = FALSE,
selected = if(!is.null(Class)) Class
)
),
column(3,
# Input: Specify the amount ----
numericInput(
paste0("amount",i),
label="Amount",
value = if(!is.null(amount)) amount else 0
)
))
})
do.call(tagList, input_list)
})
})
output$distPlot <- renderPlot({
req(reac$calc, input$update)
slices <- sapply(reac$calc, function(i) {
c(input[[paste0("amount",i)]])
})
pie(slices)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
Upvotes: 2