Reputation: 1504
I have a shiny dashboard that displays various elements (highchart and ggplot plots, datatables). Users can filter by some variables to create a "groupA" and groupB" of data. GroupA is initially all the data, GroupB is empty initially. When the user opens the dashboard, they will see a single column of elements for GroupA. By filtering they are able to move some data to groupB, which should show in new 2nd column. So each of group A and B have the same elements on the page, just a different filter is applied. If groupB becomes empty, the view will again switch to a single column of groupA elements. The column for GroupA should resize as needed to cover the whole width or half the width. I am having difficulty getting this to work in a way that is economical on code.
The answer here uses element IDs to show and hide specific elements. This would work but the dashboard has many pages and many elements per page. So it would involve a large amount of additional code.
I thought that just by putting each element in a div with class corresponding to the group, that I would be able to apply the same idea, except to use a CSS selector and catch all elements in one go. But this is not working. The CSS selector seems OK, e.g. when I use it in a jQuery statement in the console I get the expected elements.
The code below is a reprex of the issue just with buttons to show/hide groupB for simplicity, rather than depending on the data.
library(shiny)
library(shinyjs)
library(highcharter)
ui <- fluidPage(
useShinyjs(),
actionButton("hide","Hide Group B"),
actionButton("show","Show Group B"),
fluidRow(
div(class = "groupA col-sm-12", highchartOutput("plot1A")),
div(class = "groupB hidden", highchartOutput("plot1B"))
),
fluidRow(
div(class = "groupA col-sm-12", highchartOutput("plot2A")),
div(class = "groupB hidden", highchartOutput("plot2B"))
)
)
server <- function(input, output, session) {
output$plot1A <- output$plot2A <- renderHighchart({hchart(iris$Sepal.Length)})
output$plot1B <- output$plot2B <- renderHighchart({hchart(iris$Petal.Length)})
observeEvent(input$show, {
removeClass(selector = "div.groupA", "col-sm-12")
addClass( selector = "div.groupA", "col-sm-6")
removeClass(selector = "div.groupB", "hidden")
addClass( selector = "div.groupB", "col-sm-6")
})
observeEvent(input$hide, {
removeClass(selector = "div.groupA", "col-sm-6")
addClass( selector = "div.groupA", "col-sm-12")
removeClass(selector = "div.groupB", "col-sm-6")
addClass( selector = "div.groupB", "hidden")
})
}
shinyApp(ui, server)
Could anyone suggest how to make this work, or even a different method that will efficiently do what I need?
Upvotes: 3
Views: 725
Reputation: 7340
The problem is for both removeClass
and addClass
, the first positional argument is id
, not class.
To make it work as the class you want to add/remove, you need to write the argument name class = xxx
out:
removeClass(selector = ".groupA", class = "col-sm-12")
After adding all class
arguments, you will see it working but the plot is still not shown. This is because the output plot had no height on start.
By default, shiny doesn't render hidden (0 height) elements. You need to tell shiny to render it after the block is displayed
. To trigger it, you need to fire element "shown" event by javascript, but we can do it from shinyjs.
After you hide the elements, you will see the groupB is hidden, but groupA doesn't go and extend the area to cover the full width. This is because highcharter
doesn't know you made the change. You need to tell it by the window "resize" event.
So full code will look like this:
library(shiny)
library(shinyjs)
library(highcharter)
ui <- fluidPage(
useShinyjs(),
actionButton("hide","Hide Group B"),
actionButton("show","Show Group B"),
fluidRow(
div(class = "groupA col-sm-12", highchartOutput("plot1A")),
div(class = "groupB hidden", highchartOutput("plot1B"))
),
fluidRow(
div(class = "groupA col-sm-12", highchartOutput("plot2A")),
div(class = "groupB hidden", highchartOutput("plot2B"))
)
)
server <- function(input, output, session) {
output$plot1A <- output$plot2A <- renderHighchart({hchart(iris$Sepal.Length)})
output$plot1B <- output$plot2B <- renderHighchart({hchart(iris$Petal.Length)})
observeEvent(input$show, {
removeClass(selector = ".groupA", class = "col-sm-12")
addClass( selector = ".groupA", class = "col-sm-6")
removeClass(selector = ".groupB", class = "hidden")
addClass( selector = ".groupB", class = "col-sm-6")
show(selector = ".groupB")
})
observeEvent(input$hide, {
removeClass(selector = ".groupA", class = "col-sm-6")
addClass( selector = ".groupA", class = "col-sm-12")
removeClass(selector = ".groupB", class = "col-sm-6")
addClass( selector = ".groupB", class = "hidden")
runjs("$(window).trigger('resize')")
})
}
shinyApp(ui, server)
Upvotes: 2