How do I horizontally align a picker input and action buttons in a Shiny app? - shiny

The following code creates and h3 tab header, a picker input and 2 action buttons inside a class of page-header. The action buttons and slightly elevated compared to the picker input. I would like to get the action buttons to be horizontally aligned with the picker input (see red boxes in the screenshot).
How can I adjust this code to make it work.
library(shiny)
ui <- fluidPage(
div(
class = "page-header",
fluidRow(
column(
width = 8,
h3("Tab Header")
),
column(
width = 2,
pickerInput(
inputId = "picker",
label = "Picker:",
choices = c("Option 1", "Option 2", "Option 3")
)
),
column(
width = 2,
actionButton(inputId = "apply_1",
label = "Action 1",
icon = icon("play")),
actionButton(inputId = "reset_1",
label = "Action 2",
icon = icon("sync"))
)
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)

One option to horizontally align the pickerInput with the actionButtons would be to mimic the tag structure of the pickerInput, which looks like so:
<div>
<label>...</label>
<div>
....
</div>
</div>
For the label I added an invisible label by setting the color to transparent but there are probably more elegant approaches.
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
div(
class = "page-header",
fluidRow(
column(
width = 8,
h3("Tab Header")
),
column(
width = 2,
pickerInput(
inputId = "picker",
label = "Picker:",
choices = c("Option 1", "Option 2", "Option 3")
)
),
column(
width = 2,
tags$div(
tags$label("Actions:", style="color: transparent"),
tags$div(
actionButton(
inputId = "apply_1",
label = "Action 1",
icon = icon("play")
),
actionButton(
inputId = "reset_1",
label = "Action 2",
icon = icon("sync")
)
)
)
)
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)

Related

Shinydashboard. How to unselect menuItem?

I have this code:
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
shinyApp(
ui = dashboardPage(
header = dashboardHeader(userOutput("user")),
sidebar = dashboardSidebar(shinyjs::useShinyjs(),uiOutput("sidebarpanel")),
body = dashboardBody(uiOutput("body")),
title = "DashboardPage"
),
server = function(input, output) {
output$user <- renderUser({
dashboardUser(
name = "Divad Nojnarg",
image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
title = "shinydashboardPlus",
subtitle = "Author",
footer = p("The footer", class = "text-center"),
fluidRow(
actionButton("personalInfo","Personal Info")
)
)
})
observeEvent(input$personalInfo, {
output$body <- renderUI({h4("Personal Info Dahsboard (no menuItem)")})
})
output$sidebarpanel <- renderUI({
sidebarMenu(id="tabs",
menuItem("Dashboard 1", tabName = "dashboard1", icon = icon("dashboard"))
,menuItem("Dashboard 2", tabName = "dashboard2", icon = icon("dashboard"))
)
})
output$body <- renderUI({
tabItems(
tabItem(tabName ="dashboard1",
fluidRow(box(width = 12, h4("Dashboard 1 (menuItem)"))))
,tabItem(tabName ="dashboard2",
fluidRow(box(width = 12, h4("Dashboard 2 (menuItem)"))))
)
})
}
)
I would like to do two things:
First: When I click on "Personal Info" button, then, prevent the menuItem to be shadowed (I assume I need to remove the class "selected" or "active" or something like that)
Second: I want to fix this: After pressing "Personal Info" button, the menuItems do not work:
As already shown in my earlier answer here we can use a hidden menuItem to modify the body content independent from the visibly selected menuItem.
Furthermore, I'd recommend to stop using renderUI in this scenario. In general it is slower to re-render a UI element instead of updating an existing element (here we can switch to the hidden menuItem via updateTabItems - however, this applies also to e.g. using updateSelectInput instead of renderUI({selectInput(...)})). In this context you should also question whether you really need the to create the dashboardUser on the server side.
If you really need a server side generated dashboardSidebar you still should not use renderUI - There are the renderMenu() / sidebarMenuOutput() functions available for this. Please see the related docs here.
library(shiny)
library(shinyjs)
library(shinydashboard)
library(shinydashboardPlus)
shinyApp(
ui = dashboardPage(
header = dashboardHeader(userOutput("user")),
sidebar = dashboardSidebar(shinyjs::useShinyjs(),
sidebarMenu(id="tabs",
menuItem("Tab 1", tabName = "tab1", icon = icon("dashboard")),
menuItem("Tab 2", tabName = "tab2", icon = icon("dashboard")),
hidden(menuItem("Personal Tab", tabName = "personal_tab", icon = icon("dashboard")))
)),
body = dashboardBody(useShinyjs(),
tabItems(
tabItem(tabName ="tab1",
fluidRow(box(width = 12, h4("Tab 1 (menuItem)")))),
tabItem(tabName ="tab2",
fluidRow(box(width = 12, h4("Tab 2 (menuItem)")))),
tabItem(tabName ="personal_tab",
fluidRow(box(width = 12, h4("Personal Info Dahsboard (no menuItem)"))))
)
),
title = "DashboardPage"
),
server = function(input, output, session) {
output$user <- renderUser({
dashboardUser(
name = "Divad Nojnarg",
image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
title = "shinydashboardPlus",
subtitle = "Author",
footer = p("The footer", class = "text-center"),
fluidRow(
actionButton("personalInfo","Personal Info")
)
)
})
observeEvent(input$personalInfo, {
shinydashboard::updateTabItems(session, inputId = "tabs", selected = "personal_tab")
})
}
)

Remove the click trigger from flipbox

I use the function flipBox from shinydashboardPlus to create flip box and I add a button. The user have to clik on it to flip the box. But the box also flip when we click on it and I would like to desactive it I mean prevent fliping by cliking on the box (the box must flip only when we click on the button). This is what I did :
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
actionButton("swich_id", "click to swich"), # click on the button to flip the box
flipBox(
id = "id1",
front = div(
class = "text-center",
height = "300px",
width = "100%",
h1("A"),
p("a table"),
DT::DTOutput('mytable')
),
back = div(
class = "text-center",
height = "300px",
width = "100%",
h1("B"),
p("a graphe"),
plotOutput("graph")
)
)
)
),
server = function(input, output, session) {
output$mytable <- DT::renderDT({
cars[1:5, 1:2]
})
output$graph <- renderPlot({
plot(cars$speed, cars$dist)
})
observeEvent(input$swich_id, {
updateFlipBox("id1")
})
}
)
Some help would be appreciated
There is no official way to do so. We need to have our own custom hacky way to change the source code of flipBox.
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyjs)
flipBox <- function (id, front, back, trigger = c("click", "hover", "disable"), width = 6) {
if (is.null(id) || missing(id))
stop("card id cannot be null or missing!")
trigger <- match.arg(trigger)
shiny::column(width = width, shiny::tags$div(style = "position: relative",
class = "flipbox", id = id, `data-rotate` = trigger,
shiny::tags$div(class = "card-front active", style = "background-color: white;",
front), shiny::tags$div(class = "card-back", style = "background-color: white;",
back)))
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
useShinyjs(),
tags$script(HTML(
'
function _clickOnFront(el) {
$(el)
.find(".card-front")
.css({
"-webkit-transform": "perspective(1600px) rotateY(-180deg)",
transform: "perspective(1600px) rotateY(-180deg)"
})
.toggleClass("active");
$(el)
.find(".card-back")
.css({
"-webkit-transform": "perspective(1600px) rotateY(0deg)",
transform: "perspective(1600px) rotateY(0deg)"
})
.toggleClass("active");
}
function _clickOnBack(el) {
$(el)
.find(".card-front")
.css({ "-webkit-transform": "", transform: "" })
.toggleClass("active");
$(el)
.find(".card-back")
.css({ "-webkit-transform": "", transform: "" })
.toggleClass("active");
}
'
)),
actionButton("swich_id", "click to swich"), # click on the button to flip the box
flipBox(
id = "id1",
trigger = "disable",
front = div(
class = "text-center",
height = "300px",
width = "100%",
h1("A"),
p("a table"),
DT::DTOutput('mytable')
),
back = div(
class = "text-center",
height = "300px",
width = "100%",
h1("B"),
p("a graphe"),
plotOutput("graph")
)
)
)
),
server = function(input, output, session) {
output$mytable <- DT::renderDT({
cars[1:5, 1:2]
})
output$graph <- renderPlot({
plot(cars$speed, cars$dist)
})
observeEvent(input$swich_id, {
if(input$swich_id %% 2 != 0) return(runjs('_clickOnFront($("#id1"))'))
runjs('_clickOnBack($("#id1"))')
})
}
)
define our own flipBox function. Here we add one more option trigger = c("click", "hover", "disable") to allow us to choose methods other than click or hover.
Copy the flip functions from source code and define as JS functions that we have easy access with tags$script.
Use shinyjs to manually flip the box when the button is clicked.

Tabs of the menuItem, in Shinydashboard, not working when put items inside

Lets take the example of the reference: https://rstudio.github.io/shinydashboard/structure.html#sidebar-menu-items-and-tabs. When put more items in the menuItem(), your associate tab don't works anymore. I tried in this simple modification in example below and just shown the widgets' tab:
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Dashboard",
tabName = "dashboard",
icon = icon("dashboard"),
selected = TRUE,
startExpanded = TRUE,
numericInput("num1",
"Put the First Number",
value = 1,
min = 0),
numericInput("num2",
"Put the Second Number",
value = 1,
min = 0)
),
menuItem("Widgets",
icon = icon("th"),
tabName = "widgets")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content"),
fluidRow(
valueBoxOutput("box1", width = 6),
valueBoxOutput("box2", width = 6)
)
),
tabItem(tabName = "widgets",
h2("Widgets tab content")
)
)
)
# Put them together into a dashboardPage
ui <- dashboardPage(
skin = "green",
dashboardHeader(title = "Example"),
sidebar,
body
)
server <- function(input, output){
output$box1 <- renderValueBox({
valueBox(input$num1,
"First Number",
color = "aqua",
icon = icon("chart-line"))
})
output$box2 <- renderValueBox({
valueBox(input$num2,
"Second Number",
color = "aqua",
icon = icon("chart-line"))
})
}
shinyApp(ui, server)
That is because childfull menuItem behaves differently as noted here. Therefore, you need to define a menuItem or a menSubItem within that dashboard page so that your desired content can be displayed.
Try this
sidebarMenu(id = "tabs",
menuItem("Dashboard",
tabName = "dashboard",
icon = icon("tachometer-alt"),
selected = TRUE,
startExpanded = TRUE,
#icon = icon(fontawesome:::fa_tbl[[1]][505]),
menuItem("Sub-item 1", tabName = "subitem1"),
### menuSubItem("Sub-item 1", tabName = "subitem1"), ## it can be menuSubItem instead of menuItem
numericInput("num1",
"Put the First Number",
value = 1,
min = 0),
numericInput("num2",
"Put the Second Number",
value = 2,
min = 0)
),
menuItem("Widgets",
icon = icon("th"),
tabName = "widgets")
)
)
body <- shinydashboard::dashboardBody(
tabItems(
tabItem(tabName = "subitem1",
h2("Sub item1 tab content in Dashboard"),
fluidRow(
valueBoxOutput("box1", width = 6),
valueBoxOutput("box2", width = 6)
)
),
tabItem(tabName = "widgets",
h2("Widgets tab content")
)
)
)
# Put them together into a dashboardPage
ui <- shinydashboard::dashboardPage(
skin = "green",
shinydashboard::dashboardHeader(title = "Example"),
sidebar,
body
)
server <- function(input, output, session){
output$box1 <- renderValueBox({
valueBox(input$num1,
"First Number",
color = "aqua",
icon = icon("chart-line"))
})
output$box2 <- renderValueBox({
valueBox(input$num2,
"Second Number",
color = "aqua",
icon = icon("chart-line"))
})
observe({print(input$tabs)})
}
shinyApp(ui, server)

show tab only when clicked on action button

Is there a way to trigger the tab only when the user clicks on action button . Example shown below. So tab2 is hidden, but when the user clicks on action button, the tab should pop up
library(shiny)
ui <- fluidPage(
tabsetPanel(id = "tabs",
tabPanel(value = "tab1", title = "Tab 1",
tableOutput("myTable"),
actionButton("sub","Submit")
),
uiOutput("show_tab1")
# tabPanel(value = "tab2", title = "Tab 2",
# plotOutput("myPlot")
# )
)
)
server <- function(input, output, session) {
observeEvent(input$sub,{
output$show_tab1 <- renderUI({
tabPanel(value = "tab2", title = "Tab 2",
plotOutput("myPlot")
)
})
})
}
shinyApp(ui, server)
Maybe this:
library(shiny)
ui <- fluidPage(
tabsetPanel(id = "tabs",
tabPanel(value = "tab1", title = "Tab 1",
tableOutput("myTable"),
actionButton("sub","Submit")
),
tabPanel(value = "tab2", title = "Tab 2",plotOutput("myPlot"))
)
)
server <- function(input, output, session) {
observe({
hideTab(inputId = "tabs", target = "tab2")
})
observeEvent(input$sub,{
showTab(inputId = "tabs", target = "tab2")
})
}
shinyApp(ui, server)

How to remove residual when hiding a tabpanel in shiny

I would like to hide/show a tabpanel given certain conditions. When selecting "source 2", I would like to hide tab2, but the code that I used have a bug.
If I first selected "source 1", and then clicked "tab2", and changed the data source to "source 2", the "tab2" tabpanel indeed hided, but the content of "tab2" covered the contents of "tab1". How can I remove the resudual of the hided tab? Any thoughts would be highly appreciated.
library(shiny)
library(shinyjs)
runApp(list(
ui = fluidPage(
useShinyjs(),
selectInput('dataSource',h5("Please choose the data source:"), c("source 1", "source 2"), "source 1"),
tabsetPanel(
id = "navbar",
tabPanel(title = "tab1",
value = "tab1",
h1("Tab 1")
),
tabPanel(id="id2", title = "tab2",
value = "tab2",
h1("Tab 2")
)
)
),
server = function(input, output) {
observeEvent(input$dataSource,{
toggle(condition = (input$dataSource !='source 2'), selector = "#navbar li a[data-value=tab2]")
})
}
))
[the bug looks like this][1] [1]: http://i.stack.imgur.com/eOHLS.png
I could reproduce the error on my laptop.
My advice would be to use a renderUI function to create dynamically a tabsetPanel.
library(shiny)
# library(shinyjs)
runApp(list(
ui = fluidPage(
#useShinyjs(),
selectInput('dataSource',h5("Please choose the data source:"), c("source 1", "source 2"), "source 1"),
uiOutput("dynamic")
),
server = function(input, output) {
output$dynamic <- renderUI({
if (input$dataSource == "source 1") {
tabsetPanel(
id = "navbar",
tabPanel(title = "tab1",
value = "tab1",
h1("Tab 1")
),
tabPanel(id="id2", title = "tab2",
value = "tab2",
h1("Tab 2")
)
)
} else {
tabsetPanel(
id = "navbar",
tabPanel(title = "tab1",
value = "tab1",
h1("Tab 1")
)
)
}
})
}
))