updateTabsetPanel not working - r

Does anyone know why this simple code is not working?
What I am trying to do: make the structure tab active whenever users click on the run button (input$runButton). When I click the run button, the value of input$runButton gets updated, but the tab is not changed to structure.
Here is a simple reproducible example:
server.R
function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
ui.R
fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel('Variable Selection', textOutput('inputVars')),
tabPanel('Structure Result', textOutput('structure')))
)
)
Thank you!

Note that you need to assign a value to TabPanel so you can make them active using the updateTabsetPanel call, so try this:
require(shiny)
ui <- fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel(value = "inputVars",'Variable Selection', textOutput('inputVars')),
tabPanel(value = "structure",'Structure Result', textOutput('structure')))
)
)
server <- function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
runApp(shinyApp(ui, server), launch.browser = TRUE)

Note that if you are using shiny modules, that you have to refer to the correct session. For example, if a single tab is a module, the session of that tab won't be able to switch to another tab
To fix this, you can actually pass the session of the "parent" (container) of all your tabs into the constructor of the tab module, and then use that
Rough sketch of an example
shinyUI(function(request) {
source('page/search.R', local = T)
source('page/app.R', local = T)
fluidPage(
tabsetPanel(id = 'inTabset',
tabPanel(id = 'search', 'Search', searchUI('search'), value = 'search'),
tabPanel(id = 'app', 'App', appUI('app'), value = 'app')
)
)
})
shinyServer(function(input, output, session) {
source('page/search.R', local = T)
source('page/app.R', local = T)
searchSession = callModule(searchServer, 'search')
callModule(appServer, 'app', session, searchSession)
})
The shiny module
appUI = function(id) {
ns = NS(id)
tagList(
actionButton(ns('sendToHeatmap'), 'Send ortholog groups to heatmap')
)
}
appServer = function(input, output, session, parentSession, searchSession) {
# listen to a button press and switch to tab
observeEvent(input$sendToSearch, {
updateTextInput(searchSession, 'searchBox', 'funsearchterm')
updateTabsetPanel(parentSession, 'inTabset', selected = 'search')
})
}

Related

How to clear the mainPanel if a selectInput choice has changed?

I am trying to create an app that will show you results depending on a selectInput and the changes are controlled by actionButtons.
When you launch the app, you have to select a choice: Data 1 or Data 2. Once you have selected your choice (e.g. Data 1), you have to click the actionButton "submit type of data". Next, you go to the second tab, choose a column and then click "submit".
The output will be: one table, one text and one plot.
Then, if you go back to the first tab and select "Data 2", everything that you have generated is still there (as it is expected, since you didn't click any button).
However, I would like to remove everything that is in the mainPanel if I change my first selectInput as you could see it when you launch the app for the first time.
The idea is that since you have changed your first choice, you will have to do the same steps again (click everything again).
I would like to preserve and control the updates with actionButtons as I have in my code (since I am working with really long datasets and I don't want to depend on the speed of loading things that I don't want until I click the button). Nevertheless, I cannot think a way to remove everything from mainPanel if I change the choice of the first selectInput.
Does anybody have an idea how I can achieve this?
Thanks in advance
Code:
library(shiny)
library(shinyWidgets)
library(shinyFeedback)
library(DT)
library(datasets)
ui <- fluidPage(
sidebarPanel(
tabsetPanel(id="histogram",
tabPanel("Selection",
useShinyFeedback(),
selectInput(inputId = "type", label = "Select your data",
choices = c("Data 1" = "data1",
"Data 2" = "data2")),
conditionalPanel(
condition = "input.type == 'data2'",
div(style = "position:absolute;right:2.5em;",
actionButton(
inputId = "button_more_info_data2",
label = "More info",
icon = icon("info-circle"))
)
),
actionButton(
inputId = "button",
label = "Submit type of data",
icon = icon("check")
)
),
tabPanel("Pick the column",
br(),
selectizeInput(inputId = "list_columns", label = "Choose the column:", choices=character(0)),
actionButton(
inputId = "button2",
label = "Submit")
))
),
mainPanel(
dataTableOutput("table"),
textOutput("text"),
plotOutput("myplot")
)
)
server <- function(input, output, session) {
observeEvent(input$type,{
feedbackWarning(inputId = "type",
show = ("data2" %in% input$type),
text ="This data is... Please, be careful..."
)
})
mydata <- reactive({
if(input$type == "data1"){
mtcars
}else{
iris
}
}) %>% bindEvent(input$button2)
# This is to generate the choices (gene list) depending on the user's input.
observeEvent(input$button, {
updateSelectizeInput(
session = session,
inputId = "list_columns",
choices = colnames(trees), options=list(maxOptions = length(colnames(trees))),
server = TRUE
)
})
output$table <- renderDataTable({
req(input$button2)
mydata()
})
output$text <- renderText({
req(input$button2)
input$list_columns
})
output$myplot <- renderPlot({
req(input$button2, input$button)
hist(trees[,input$list_columns])
})
}
if (interactive())
shinyApp(ui, server)
Here is an example using a reset button - using the selectInput you'll end up with a circular reference:
library(shiny)
library(shinyWidgets)
library(shinyFeedback)
library(DT)
library(datasets)
ui <- fluidPage(sidebarPanel(tabsetPanel(
id = "histogram",
tabPanel(
"Selection",
useShinyFeedback(),
selectInput(
inputId = "type",
label = "Select your data",
choices = c("Data 1" = "data1",
"Data 2" = "data2")
),
conditionalPanel(
condition = "input.type == 'data2'",
div(
style = "position:absolute;right:2.5em;",
actionButton(
inputId = "button_more_info_data2",
label = "More info",
icon = icon("info-circle")
)
)
),
actionButton(
inputId = "button",
label = "Submit type of data",
icon = icon("check")
),
actionButton(
inputId = "reset",
label = "Reset",
icon = icon("xmark")
)
),
tabPanel(
"Pick the column",
br(),
selectizeInput(
inputId = "list_columns",
label = "Choose the column:",
choices = character(0)
),
actionButton(inputId = "button2",
label = "Submit")
)
)),
mainPanel(
dataTableOutput("table"),
textOutput("text"),
plotOutput("myplot")
))
server <- function(input, output, session) {
observeEvent(input$type, {
feedbackWarning(
inputId = "type",
show = ("data2" %in% input$type),
text = "This data is... Please, be careful..."
)
})
mydata <- reactiveVal(NULL)
observe({
if (input$type == "data1") {
mydata(mtcars)
} else if (input$type == "data2") {
mydata(iris)
} else {
mydata(data.frame())
}
}) %>% bindEvent(input$button2)
observeEvent(input$reset, {
mydata(data.frame())
})
# This is to generate the choices (gene list) depending on the user's input.
observeEvent(input$button, {
updateSelectizeInput(
session = session,
inputId = "list_columns",
choices = colnames(trees),
options = list(maxOptions = length(colnames(trees))),
server = TRUE
)
})
output$table <- renderDataTable({
req(input$button2)
mydata()
})
output$text <- renderText({
req(input$button2)
input$list_columns
})
output$myplot <- renderPlot({
req(input$button2, input$button)
hist(trees[, input$list_columns])
})
}
shinyApp(ui, server)

How to have a user input text and create a list with shiny? R

I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)

Shiny App: Adding unlimited number of input bars

I want to build an app in which the user can add as many as input slots as he wants. I could only build an app that let the user to add only one more input slot. Here is my code:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectizeInput("a", "Something", choices = "blah blah"),
uiOutput("b"),
actionButton(inputId = "rm", label = "-"),
actionButton(inputId = "add", label = "+"),
),
mainPanel(
textOutput("test")
)
)
)
server <- function(input, output) {
observeEvent(input$add ,{
output$b <- renderUI({
selectizeInput("b", "Another thing", choices = "blah blah")
})
})
observeEvent(input$rm ,{
output$b <- renderUI({
NULL
})
})
}
shinyApp(ui = ui, server = server)
I have no idea how I can extend this to let the user add as many as input slots as he wants. Is this even possible?
We can try this approach:
We can access new added inputs with input$a1, input$a2 ... input$ax
Edit: added an observer to see the new inputs generated in the console. The first input created after pressing + button will be called input$a1.
observe({
print(names(input))
print(input$a1)
})
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectizeInput("a", "Something", choices = "blah blah"),
actionButton(inputId = "rm", label = "-"),
actionButton(inputId = "add", label = "+"),
),
mainPanel(
textOutput("test")
)
)
)
server <- function(input, output) {
input_counter <- reactiveVal(0)
observeEvent(input$add, {
input_counter(input_counter() + 1)
insertUI(
selector = "#rm", where = "beforeBegin",
ui = div(id = paste0("selectize_div", input_counter()), selectizeInput(paste0("a", input_counter()), label = "Another thing", choices = c("bla", "blabla")))
)
})
observeEvent(input$rm, {
removeUI(
selector = paste0("#selectize_div", input_counter())
)
input_counter(input_counter() - 1)
})
observe({
print(names(input))
print(input$a1)
})
}
shinyApp(ui, server)

Separating fileInput from radioButtons into shiny code

When running the code below, you will notice that I have two options below. If you press the Excel option, a fileInput will appear right below the radioButtons. However, I would like to know if it is possible to separate fileInput from radioButtons. I will insert an image to clarify what I want. See that they are separated.
Executable code below:
library(shiny)
library(dplyr)
library(shinyjs)
library(shinythemes)
library(readxl)
ui <- fluidPage(
shiny::navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
br(),
tabPanel("PAGE1",
sidebarLayout(
sidebarPanel(
radioButtons("button",
label = h3("Data source"),
choices = list("Excel" = "Excel",
"Database" = "database"),
selected = "File"),
uiOutput('fileInput'),
),
mainPanel(
)))))
server <- function(input, output) {
observe({
if(is.null(input$button)) {
}else if (input$button =="Excel"){
output$fileInput <- renderUI({
fileInput("file",h4("Import file"), multiple = T, accept = ".xlsx")
})
} else if(input$button=="database"){
output$fileInput <- NULL
} else {
output$fileInput <- NULL
}
})
}
shinyApp(ui = ui, server = server)
Example:
I left it in red to specify the space
A possible workaround could be to use fluidRow with two columns to simulating a sidebarPanel with a mainPanel.
Notice that I wrapped the inputs in a div(class = "well well-lg") for the background.
App
library(shiny)
library(dplyr)
library(shinyjs)
library(shinythemes)
library(readxl)
ui <- navbarPage(
theme = shinytheme("flatly"), collapsible = TRUE,
br(),
tabPanel(
"PAGE1",
fluidRow(
column(
width = 6,
fluidRow(div(
class = "well well-lg",
radioButtons("button",
label = h3("Data source"),
choices = list(
"Excel" = "Excel",
"Database" = "database"
),
selected = "File"
)
)),
fluidRow(
uiOutput("fileInput")
)
),
column(
width = 6,
tableOutput("iris")
)
)
)
)
server <- function(input, output) {
output$iris <- renderTable({
iris
})
observe({
if (is.null(input$button)) {
} else if (input$button == "Excel") {
output$fileInput <- renderUI({
div(class = "well well-lg", fileInput("file", h4("Import file"), multiple = T, accept = ".xlsx"))
})
} else if (input$button == "database") {
output$fileInput <- NULL
} else {
output$fileInput <- NULL
}
})
}
shinyApp(ui = ui, server = server)

Access sessions for action link in Nested Tabset and Tabpanels in R shiny

Here I'm trying to create a actionlink between tabs, but I have many nested tabs within and since I'm calling the links from the nested tabs itself and not the main session, I'm not able to place the id's correctly.
I've looked into this question : Question , but this works for only the main session.
Here's a part of my reproducible code:
ui <- fluidPage(
navbarPage(id = "Navbar",
tabPanel("About",..
actionLink("link_to_overview", "Let's start with the Overview!"), <--- This works
),
tabPanel("Overview",
tabsetPanel(id = "Tab_ov",
tabPanel("Flights",..
actionLink("link_to_airlines", "Let's go to the Airlines!"),<--- This doesn't work
),
tabPanel("Airlines",..
actionLink("link_to_domestic_stats", "Let's go to the Domestic!") <--- This doesn't work
),
)),
tabPanel("Statistics",
tabsetPanel(id = "stats_tab",
tabPanel("Domestic",..
),
tabPanel("International",..),
))
))
server <- function(input, output, session) {
observeEvent(input$link_to_overview, {
newvalue <- "Overview"
updateTabItems(session, "Navbar", newvalue)
})
observeEvent(input$link_to_airlines, {
updateTabsetPanel(session, inputId = 'Flights', selected = 'Tab_ov')
updateTabsetPanel(session, inputId = 'Overview', selected = 'Airlines')
})
observeEvent(input$link_to_domestic_stats, {
updateTabsetPanel(session, inputId = 'Overview', selected = 'Statistics')
updateTabsetPanel(session, inputId = 'stats_tab', selected = 'Domestic')
})
}
Try this:
library(shiny)
library(tidyverse)
ui <- fluidPage(navbarPage(
id = "Navbar",
tabPanel(
"About",
actionLink("link_to_overview", "Let's start with the Overview!")
),
tabPanel("Overview",
tabsetPanel(
tabPanel(
"Flights",
value = 'flights',
actionLink("link_to_airlines", "Let's go to the Airlines!")
),
tabPanel(
"Airlines",
value = 'airlines',
actionLink("link_to_domestic_stats", "Let's go to the Domestic!")
), id = "Tab_ov"
),value = 'ovview'),
tabPanel(
"Statistics",
tabsetPanel(
tabPanel("Domestic", value = 'domestic'),
tabPanel("International", ''),
id = "stats_tab")
)
))
server <- function(input, output, session) {
observeEvent(input$link_to_overview, {
updateTabsetPanel(session, "Navbar", 'ovview')
})
observeEvent(input$link_to_airlines, {
updateTabsetPanel(session, inputId = 'Tab_ov', selected = 'airlines')
})
observeEvent(input$link_to_domestic_stats, {
updateTabsetPanel(session, inputId = 'Navbar', selected = 'Statistics')
updateTabsetPanel(session, inputId = 'stats_tab', selected = 'domestic')
})
}
shinyApp(ui, server)

Resources