At the moment the app ends when the user clicks on a button Q. I would like this app to end when the user clicks Quit on the navbar. Unfortunately I can't figure out how to do this. Will be thankful for any help!
EDIT:
It would be great to know how to shift Quit tab to the right :)
ui <- shinyUI(navbarPage(title = "Test",
tabPanel(title = "Content",
actionButton(inputId = "quit", label = "Quit")
),
tabPanel(title = "Quit", icon = icon("circle-o-notch"))
)
)
server <- shinyServer(function(input,output) {
observe({
if (input$quit == 1) stopApp()
})
})
shinyApp(ui, server)
The solution for your problem is to create an id for the navbar, with that, you can call observer like you did but changing the input. The only problem is to identificate that you need to create a new id for the navbarPage.
shinyApp(
ui = navbarPage(title = "Test", id="navbar",
tabPanel(title = "Content"),
tabPanel(title = "Quit", value="stop", icon = icon("circle-o-notch"))
), #Close UI
server = function(input,output,session) {
observe({
if (input$navbar == "stop")
stopApp()
})
} #Close server
) #Close shinyApp
Related
Good days, I am programming in Rstudio, using shiny, and I wanted to generate an alert that is activated only when I want to leave a tabPanel without completing a condition, but not if I do not enter the tabPanel before, this is the way I found. The problem is that every time that I leave the Panel 1 without fulfilling the condition of completing text, alerts are generated that are accumulating (1 alert the first time, two the second, three the third, etc.) I wanted to consult if somebody knows why it is this and how to avoid it.
thank you very much
library(shiny)
library(ggplot2)
library(shinyalert)
ui <- fluidPage(
tabsetPanel(
id = "tabselected",
tabPanel("Tab2",""),
tabPanel("Tab1", textInput("requiredText", "Required Text"))
))
server <- function(input, output, session) {
observe({
req(input$tabselected == "Tab1")
observeEvent(
input$tabselected,
if (input$tabselected != "Tab1" & !isTruthy(input$requiredText)) {
shinyalert(title = "Save your work before changing tab",
type = "warning",
showConfirmButton = TRUE
)
updateTabsetPanel(session, inputId = "tabselected", selected = "Tab1")
}
)
}
)
}
shinyApp(ui = ui, server = server)
Is this the behavior you desire? Your example was recursive so you had reoccurring popup event. We can create a reactiveValues variable to keep track of the events, like so:
library(shiny)
library(ggplot2)
library(shinyalert)
ui <- fluidPage(
tabsetPanel(
id = "tabselected",
tabPanel("Tab2",""),
tabPanel("Tab1", textInput("requiredText", "Required Text"))
))
server <- function(input, output, session) {
v <- reactiveValues(to_alert = FALSE)
observeEvent(input$tabselected,{
if (input$tabselected != "Tab1" & !isTruthy(input$requiredText)) {
v$to_alert <- TRUE
}else{
v$to_alert <- FALSE
}
},ignoreInit = TRUE)
observeEvent(v$to_alert,{
if (v$to_alert){
shinyalert(title = "Save your work before changing tab", type = "warning",showConfirmButton = TRUE)
updateTabsetPanel(session, inputId = "tabselected", selected = "Tab1")
}
})
}
shinyApp(ui = ui, server = server)
I am trying to implement something similar to this within the app and not at the browser level as described here.
After capturing the value of the new tab (tabPanel value) selected, could not display the confirmation message before switching to the newly selected tab to display its content.
library(shiny)
library(ggplot2)
library(shinyalert)
ui <- fluidPage(useShinyalert(),
tabsetPanel(id = "tabselected",
tabPanel("Tab1"),
tabPanel("Tab2",plotOutput("plot"))
)
)
server <- function(input, output) {
observeEvent(input$tabselected, {
if(input$tabselected == "Tab2")
{
shinyalert(title = "Save your work before changing tab", type = "warning", showConfirmButton = TRUE)
output$plot <- renderPlot({ ggplot(mtcars)+geom_abline() })
}
})
}
shinyApp(ui = ui, server = server)
You can simply redirect to Tab1 via updateTabsetPanel as long as your desired condition is met.
Here is an example requiring the user to type something in the textInput before it's allowed to switch the tab.
library(shiny)
library(ggplot2)
library(shinyalert)
ui <- fluidPage(useShinyalert(),
tabsetPanel(
id = "tabselected",
tabPanel("Tab1", p(), textInput("requiredText", "Required Text")),
tabPanel("Tab2", p(), plotOutput("plot"))
))
server <- function(input, output, session) {
observeEvent(input$tabselected, {
if (input$tabselected == "Tab2" && !isTruthy(input$requiredText)) {
updateTabsetPanel(session, inputId = "tabselected", selected = "Tab1")
shinyalert(title = "Save your work before changing tab",
type = "warning",
showConfirmButton = TRUE)
output$plot <- renderPlot({
ggplot(mtcars) + geom_abline() + ggtitle(req(input$requiredText))
})
}
})
}
shinyApp(ui = ui, server = server)
By the way an alternative approach wpuld be using showTab and hideTab to display the tabs only if all conditions are fulfilled.
I want to execute rest of shiny app code only when modal dialog box is closed. How can I achieve this?
Here simple code:
# ui.R
actionButton("loadData", label = "Button", icon = icon("mail-forward"))
# server.R
observeEvent(input$loadData, {
showModal(modalDialog(
title = modal.title,
textInput("newName", "Enter file name:", value = ""),
easyClose = TRUE,
footer = list(
actionButton("confirmName", "OK"),
modalButton("Cancel"))
))
# ...code to be executed after modal is closed...
})
Create an event handler that executes code when the OK action button has been clicked, and also closes the modal using removeModal.
library(shiny)
ui <- fluidPage(
actionButton("loadData", label = "Button", icon = icon("mail-forward")),
verbatimTextOutput("filename")
)
server <- function(input, output, session) {
observeEvent(input$loadData, {
showModal(modalDialog(
title = "title",
textInput("newName", "Enter file name:", value = ""),
easyClose = TRUE,
footer = list(
actionButton("confirmName", "OK"),
modalButton("Cancel"))
))
})
output$filename <- eventReactive(input$confirmName, {
message("Closing modal")
removeModal()
input$newName
})
}
shinyApp(ui, server)
There's an example of this in the docs: https://shiny.rstudio.com/reference/shiny/latest/modalDialog.html
I'm building a shiny app in which a query from textInput is made when the user clicks on the "search" action button. I'd like that button to be disabled if the textInput box is empty. I'm using shinyjs::toggleState() here, but I can't figure out what logic it needs to apply to see that the text box is empty. In my reproducible file below, the logic I put in place is is.null(input$query). I've also tried with is.na(input$query), length(input$query) == 0, and input$query == '', all without success What should I put there instead?
Here's the app.r file:
library(shiny)
library(shinyjs)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
useShinyjs(),
textInput(inputId = "query", label = "Enter query:", value = ""),
actionButton(inputId = "search", label = "Search", icon = icon("search"))
),
mainPanel()
)
)
server <- function(input, output) {
observe({
toggleState("search", !is.null(input$query))
})
}
shinyApp(ui = ui, server = server)
Something like this do?
observe({
if(is.null(input$query) || input$query == ""){
disable("search")
}
else{
enable("search")
}
})
As per #Sagar you can also do:
observe({
toggleState("search", input$query != "" | is.null(input$query))
})
or
observeEvent(input$query,{
toggleState("search", input$query != "" | is.null(input$query))
})
I have been using the approach suggested by #wch on SO to close the browser window when clicking an action button in a Shiny app. Works great.
I would now like to stop my app and close the bowser window (in Chrome) when clicking an element in the navbar. Below the tabPanel call I'm using
tabPanel(title = "", value = "Stop", icon = icon("power-off"))
I use an observer to stop the app when the value of input$navbar == "Stop" (i.e, when the icon in the navbar is selected) but I'm not sure how to activate the window.close() call.
Code for action button to close browser windows by #wch
tags$button(
id = 'close',
type = "button",
class = "btn action-button",
onclick = "window.close();",
"Close window"
)
EDIT:
Found a work-around that does what I want.
tabPanel(tags$a(id = "quitApp", href = "#", class = "action-button",
list(icon("power-off"), ""), onclick = "window.close();"))
Unfortunately it leads to a rather badly aligned navbar. I asked a related question on the Shiny google group
You can use the shinyjs package to easily call javascript functions, which is essentially all you need to do. Disclaimer: I wrote that package. Here's the code to do what you want:
library(shinyjs)
jscode <- "shinyjs.closewindow = function() { window.close(); }"
runApp(shinyApp(
ui = tagList(
useShinyjs(),
extendShinyjs(text = jscode),
navbarPage(
"test",
id = "navbar",
tabPanel(title = "tab1"),
tabPanel(title = "", value = "Stop", icon = icon("power-off"))
)
),
server = function(input, output, session) {
observe({
if (input$navbar == "Stop") {
js$closewindow();
stopApp()
}
})
}
))
EDIT:
If you don't want to use a JS package, you can do the same thing with native shiny:
jscode <- "Shiny.addCustomMessageHandler('closeWindow', function(m) {window.close();});"
runApp(shinyApp(
ui = tagList(
tags$head(tags$script(HTML(jscode))),
navbarPage(
"test",
id = "navbar",
tabPanel(title = "tab1"),
tabPanel(title = "", value = "Stop", icon = icon("power-off"))
)
),
server = function(input, output, session) {
observe({
if (input$navbar == "Stop") {
session$sendCustomMessage(type = "closeWindow", message = "message")
stopApp()
}
})
}
))