Home > Mobile >  A Tab that become visible if an action button condition is met in R shiny not updating the rendered
A Tab that become visible if an action button condition is met in R shiny not updating the rendered

Time:08-29

I am trying to create a ShinyApp with two tabs ( a "Home" tab and a "Info" tab, the second of which is hidden tab hat only gets activated or visible once the action button "Display Data" is clicked), and a sidebar that has got a dropdown menu. It is meant to just show a constant " Hello and Welcome" message in the home tab, and depending on the user option, display the data in the "Info" tab when and if action button is clicked (otherwise it won't display the second "Info" tab and just show the "Home" tab).

Now the problem is that the first time I run the app, it's working as desired and displaying the relevant rendered data table in the "Info" tab based on the user selection from the drop down menu and mainly clicking the "Display Data" button afterwards. However, if the user then selects another option from the drop down menu and clicks the "Display Data" action button, it's not updating or changing the rendered data table in the "Info" tab accordingly. That is basically what I need help with (being able to show updated rendered table every time user selects another option from the drop down menu), as I am new to Shiny and recently started learning it. Any help will be much appreciated and thanks in advance.

Here is the code I have so far for creating the data frame from which the table is rendered and the shiny global.R, ui.R and server.R code.

# global.R

cities <- data.frame("Continent" =
    c('Europe','Europe', 'Europe', 'America', 'America', 'Africa', 'Africa', 'Asia', 'Asia'), 
  "City" = c('Berlin','London','Madrid','Washington DC', 'Los Angeles', 'Cairo', 'Pretoria', 'Shanghai', 'Dubai'),
  "Population"= c(3620340,8821025,3223000,700000,3973000,9540000,2473000,26000000,3331000))

selection_function <- function(continent_choice) {
  if (!continent_choice == "All"){
    data <- cities[cities$Continent==continent_choice, ]
  } else {
    data <- cities
  }
  return (data)
}


# ui.R

library(shiny)
library(shinyjs)

shinyUI(fluidPage(
  
  # Application title
  titlePanel(h1("My App")),
  
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "id1", 
                  label = HTML("Please select a continent"),
                  choices = c("All", sort(unique(cities$Continent)))
      ),
      tags$br(), tags$br(),
      actionButton("action1", "Display Data"),
      tags$br(), tags$br()
    ),

    # Main Panel
    mainPanel(
      tabsetPanel(id="the_id",
                  tabPanel("Home", br(),
                           h3("Hello and welcome, this is my App"),
                           tags$br(), tags$br(),
                           h5("Navigate through the options on the left")
                  )
      )
      
      
    )
  ))
)

server.R

library(shiny)
library(DT)

shinyServer(function(input, output) {
  
  
  observeEvent(input$action1,{
    the_continent <- selection_function(input$id1)
    appendTab(inputId = "the_id", 
              tabPanel("Info", br(),
                       DT::renderDataTable({
                         the_continent
                       }) ))
    
  }, once = TRUE )
  
})

Finally, I would also like to ask if there are any other better ways of trying to do what I am doing (like maybe doing this with conditionalPanel as opposed to the append tab option that I am doing)? I am saying so, because I think it's much better to handle things in the client side instead of the server side. Thanks once again.

CodePudding user response:

Edit

We can use dataTableProxy to create a proxy table and replace the data only when the button is pressed. This way we also prevent loosing the "state" of the table when new changes happen.

App:

# global.R

library(shiny)
library(shinyjs)
library(DT)


cities <- data.frame(
  "Continent" =
    c("Europe", "Europe", "Europe", "America", "America", "Africa", "Africa", "Asia", "Asia"),
  "City" = c("Berlin", "London", "Madrid", "Washington DC", "Los Angeles", "Cairo", "Pretoria", "Shanghai", "Dubai"),
  "Population" = c(3620340, 8821025, 3223000, 700000, 3973000, 9540000, 2473000, 26000000, 3331000)
)

selection_function <- function(continent_choice) {
  if (!continent_choice == "All") {
    data <- cities[cities$Continent == continent_choice, ]
  } else {
    data <- cities
  }
  return(data)
}


# ui.R

ui <- fluidPage(

  # Application title
  titlePanel(h1("My App")),
  useShinyjs(),

  # Sidebar
  sidebarLayout(
    sidebarPanel(
      selectInput(
        inputId = "id1",
        label = HTML("Please select a continent"),
        choices = c("All", sort(unique(cities$Continent)))
      ),
      tags$br(), tags$br(),
      actionButton("action1", "Display Data"),
      tags$br(), tags$br()
    ),

    # Main Panel
    mainPanel(
      tabsetPanel(
        id = "the_id",
        tabPanel(
          "Home", br(),
          h3("Hello and welcome, this is my App"),
          tags$br(), tags$br(),
          h5("Navigate through the options on the left")
        )
      )
    )
  )
)


server <- function(input, output, session) {
  table <- reactive({
    the_continent <- selection_function(input$id1)
  })

  observeEvent(input$action1,
    {
      the_continent <- selection_function(input$id1)
      appendTab(
        inputId = "the_id",
        tabPanel(
          "Info", br(),
          DT::DTOutput("dt_table")
        )
      )

      output$dt_table <- DT::renderDT({
        isolate(table())
      })
      updateTabsetPanel(
        session  = session,
        inputId  = "the_id",
        selected = "Info"
      )
    },
    once = TRUE
  )

  proxy <- dataTableProxy("dt_table")

  observeEvent(input$action1, {
    replaceData(
      proxy          = proxy,
      data           = table(),
      resetPaging    = FALSE,
      clearSelection = FALSE
    )
  })
}


shinyApp(ui, server)

enter image description here

Another way to do it is to call DT::renderDT inside the observeEvent but outside the apendTab function. The downside is that the datatable will be reset every time the button is pressed.

# global.R

library(shiny)
library(shinyjs)


cities <- data.frame(
  "Continent" =
    c("Europe", "Europe", "Europe", "America", "America", "Africa", "Africa", "Asia", "Asia"),
  "City" = c("Berlin", "London", "Madrid", "Washington DC", "Los Angeles", "Cairo", "Pretoria", "Shanghai", "Dubai"),
  "Population" = c(3620340, 8821025, 3223000, 700000, 3973000, 9540000, 2473000, 26000000, 3331000)
)

selection_function <- function(continent_choice) {
  if (!continent_choice == "All") {
    data <- cities[cities$Continent == continent_choice, ]
  } else {
    data <- cities
  }
  return(data)
}


# ui.R

ui <- fluidPage(
  
  # Application title
  titlePanel(h1("My App")),
  useShinyjs(),
  
  # Sidebar
  sidebarLayout(
    sidebarPanel(
      selectInput(
        inputId = "id1",
        label = HTML("Please select a continent"),
        choices = c("All", sort(unique(cities$Continent)))
      ),
      tags$br(), tags$br(),
      actionButton("action1", "Display Data"),
      tags$br(), tags$br()
    ),
    
    # Main Panel
    mainPanel(
      tabsetPanel(
        id = "the_id",
        tabPanel(
          "Home", br(),
          h3("Hello and welcome, this is my App"),
          tags$br(), tags$br(),
          h5("Navigate through the options on the left")
        )
      )
    )
  )
)


server <- function(input, output) {
  table <- reactive({
    the_continent <- selection_function(input$id1)
  })
  
  observeEvent(input$action1,
               {
                 the_continent <- selection_function(input$id1)
                 appendTab(
                   inputId = "the_id",
                   tabPanel(
                     "Info", br(),
                     DT::DTOutput("dt_table")
                   )
                 )
                 
                 output$dt_table <- DT::renderDT({
                   input$action1
                   isolate(table())
                 })
               },
               once = TRUE
  )
}


shinyApp(ui, server)
  • Related