Addressing Multiple Inputs in Shiny

Addressing multiple inputs in shiny

You can use names on input :

grep(pattern = "d+[[:digit:]]", x = names(input), value = TRUE)

A working example :

library("shiny")
ui <- fluidPage(
fluidRow(
column(
width = 6,
lapply(
X = 1:6,
FUN = function(i) {
sliderInput(inputId = paste0("d", i), label = i, min = 0, max = 10, value = i)
}
)
),
column(
width = 6,
verbatimTextOutput(outputId = "test")
)
)
)
server <- function(input, output){
output$test <- renderPrint({
sapply(grep(pattern = "d+[[:digit:]]", x = names(input), value = TRUE), function(x) input[[x]])
})
}
shinyApp(ui = ui, server = server)

dplyr multiple inputs from Shiny

Principal == input$selectPrincipal | input$selectPrincipal == "All"

R Shiny - How to update a SINGLE input with Multiple input methods

Do you mean something like this?

ui <- fluidPage(
numericInput("year", "", min = 1979, max = 2017, value = 1979),
sliderInput("year2", "Select Year", min = 1979, max = 2017, value = 1979)
)

#===================================================

server <- function(input, output, session) {
observeEvent(input$year, {
updateSliderInput(session, "year2", value = input$year)
})

observeEvent(input$year2, {
updateNumericInput(session, "year", value = input$year2)
})
}

shinyApp(ui, server)

Multiple inputs to reactive value R Shiny

You could get rid of the inPath reactive and just use values$inDir instead.
With req() you'll wait until values are available. Otherwise you'll get the same error (invalid 'path' argument).

The reactive triggers right away, while the eventReactive will wait until the given event occurs and the eventReactive is called.

And if(is.null(values$inDir)) return() won't work correctly, as it will return NULL if values$inDir is NULL, which is then passed to list.files. And list.files(NULL) gives the error: invalid 'path' argument.

Replace it with req(values$inDir) and you won't get that error.

And your example with 2 inPath - eventReactive's won't work, as the first one will be overwritten by the second one, so input$button1 won't trigger anything.

library(shiny)

ui <- fluidPage(
actionButton("button1", "First Button"),
textInput("inText", "Input Text"),
actionButton("button2", "Second Button"),
textOutput("outText"),
textOutput("outFiles")
)

server <- function(input, output) {
values <- reactiveValues(inDir = NULL)

observeEvent(input$button1, {values$inDir <- tcltk::tk_choose.dir()})
observeEvent(input$button2, {values$inDir <- input$inText})
output$outText <- renderText(values$inDir)

fileList <- reactive({
req(values$inDir);
list.files(path=values$inDir)
})

output$outFiles <- renderPrint(fileList())
}

shinyApp(ui, server)

You could also use an eventReactive for button1 and an observeEvent for button2, but note that you need an extra observe({ inPath() }) to make it work. I prefer the above solution, as it is more clear what's happening and also less code.

server <- function(input, output) {
values <- reactiveValues(inDir = NULL)

inPath = eventReactive(input$button1, {values$inDir <- tcltk::tk_choose.dir()})
observe({
inPath()
})

observeEvent(input$button2, {values$inDir <- input$inText})
output$outText <- renderText(values$inDir)

fileList <- reactive({
req(values$inDir);
list.files(path=values$inDir)
})

output$outFiles <- renderPrint(fileList())
}

And to illustrate why if(is.null(values$inDir)) return() won't work, consider the following function:

test <- function() { if (TRUE) return() }
test()

Although the if-condition evaluates to TRUE, there is still gonna be a return value (in this case NULL), which will be passed on to the following functions and in your case list.files, which will cause the error.

How to select multiple input case using if statement in Shiny?

input$att is a vector with potentially two elements, but you're asking if it's equal to a vector of one element. replace the == with %in% (and switch the order):

if ("magnitude" %in% input$att & "depth" %in% input$app) ...

An alternative, probably better solution would be to replace the equal sign with identical, which isn't vectorized:

if(identical(input$att,"magnitude")) {...}
else if(identical(input$att,"depth")) {...}
else if (identical(input$att, c("magnitude", "depth") | identical(input$att, c("depth","magnitude")) {...}

Update multiple shiny apps inputs with different input widget types

Unfortunately there is no generic updateInput function in shiny. It is still possible to build a wrapper that identifies a certain name to a certain input type, but that will also require to know which argument is allowed or no. For example, updateActionButton doesn't have value or choices as an argument so we'll need numerous if statements.

A possible workaround is to take advantage of renderUI and directly pass the stored values. The only downside is that some functions like SliderInput throw an error when some arguments are NULL, so an if statement is needed to appoint a default value for the first time the app runs. Alternatively a mock app can be executed once to only fill the first values.

Code:

library(shiny)
library(shinyStore)
library(tidyverse)

ui <- fluidPage(
initStore("store", "shinyStore-ex1"),
uiOutput('ui_all'))

server <- function(input, output, session) {



output$ui_all <- renderUI({
tagList(
headerPanel("shinyStore Example"),
sidebarLayout(
sidebarPanel = sidebarPanel(
textInput(inputId = "Text1", label = "Enter some texts",value = input$store$Text1)
),
mainPanel = mainPanel(
fluidRow(
numericInput(inputId = "Number1", label = "Enter a number", value = input$store$Number1),
sliderInput(inputId = "Slider1", label = "Pick a number", min = 0, max = 100, value = if(is.null(input$store$Slider1)){50} else{input$store$Slider1}),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
))
})


input_nms <- map(c('Text', 'Number', 'Slider'), ~str_c(.x, 1:1)) %>%
reduce(c)

#or if every type of input is repeteated n different times.
# input_nms <- map2(c('Text', 'Number', 'Slider'), c(n1, n2, n3), ~str_c(.x, 1:.y)) %>%
# reduce(c)


observeEvent(input$save, {
input_nms %>%
walk(~updateStore(session = session, name = .x, value = isolate(input[[.x]])))
session$reload() #to force the UI to render again with the new values
})

observeEvent(input$clear, {
input_nms %>%
walk2(c(NA, NA, 50), ~updateStore(session = session, name = .x, value = .y))
})
}

shinyApp(ui, server)

R Shiny filter with two inputs

First of all, I refactored your code, since it was really hard to read for me. (I also merged the two files into app.R, but it's not necessary)

Second: you use the wrong logical operator. There are two problems with using || in this case:

  1. You need the and &, && operator, instead of the or |, ||, since you want to filter by 2 conditions.

  2. The longer form evaluates left to right examining only the first element of each vector. This is not what you want, you need to check all elements of the vector if they are equal to the filtering condition.

So you'd write subset(data, data$country == input$countryIn & data$code == input$code), but it's still not gonna work since the default value of textInput is an empty string (""), which won't yield any results.

So there are two scenarios: When the data is only filtered by the code, and another where both filters are in action. You could use an if statement for this:

  output$tbl <- renderTable( {
if(input$code == "") subset(data, data$country == input$countryIn)
else subset(data, data$country == input$countryIn & data$code == input$code)
})

Please note, that you may want to delay validation, since slowly typing into the textInput field will refresh the table.

Complete code:

library(shiny)

id <- 1:6
country <- c("Germany", "UK", "USA", "Poland", "UK", "UK")
code <- c(255,124,234,751,124,326)
data <- data.frame(id, country, code)

ui <- fluidPage(
titlePanel("This is my website"),
sidebarLayout(
sidebarPanel(
uiOutput(outputId="country"),
textInput(inputId="code",label="writte code")),
mainPanel(tableOutput(outputId="tbl"))
)
)

server <- function(input,output) {
output$country <- renderUI( {
selectInput(inputId ="countryIn", label="Choose country", choices=unique(data$country))
})

output$tbl <- renderTable( {
if(input$code == "") subset(data, data$country == input$countryIn)
else subset(data, data$country == input$countryIn & data$code == input$code)
})
}

shinyApp(ui, server)


Related Topics



Leave a reply



Submit