Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buttons updating tabs or panes do not update the input value #172

Closed
gabrifc opened this issue Nov 23, 2019 · 3 comments
Closed

Buttons updating tabs or panes do not update the input value #172

gabrifc opened this issue Nov 23, 2019 · 3 comments

Comments

@gabrifc
Copy link

gabrifc commented Nov 23, 2019

Hi! First of all, thanks for developing yonder. It is a joy to use and have used it in many projects. Here is my current problem:

Externally updating tabs or navigation panes does not update the value reported by the input, despite the changing the tab. This prevents using conditional statements that depends on whih tab is active at the moment.

Example 1: Updating a tabsetPanel via external actionButton without yonder. The value of input$gene_reads is updated when the actionButton is clicked.

## Imports ---------------------------------------------------------------------
library("shiny")
# UI & Bootstrap 4
library('yonder')

ui <- fluidPage(
  title = "actionButton",
  # columns(
  #   column(width = 12,
  #          h2("action buttons"))
  # ),
  tabsetPanel(id = "gene_reads",
              tabPanel(id = "gene_reads_preview",
                       value = "gene_reads_preview",
                       title = "Gene Reads Preview",
                       h2("Preview Tab"),
                       textOutput("gene_reads_preview_UI"),
                       actionButton("to_QC",
                                    "go to QC tab")
              ),
              tabPanel(id = "gene_reads_QC",
                       value = "gene_reads_QC",
                       title = "Gene Reads Quality Control",
                       h2("QC Tab"),
                       textOutput("gene_reads_QC_UI"),
                       actionButton("to_preview",
                                    "go to preview tab"),
                       actionButton("to_EDA",
                                    "go to eda tab")),
              tabPanel(id = "gene_reads_EDA",
                       value = "gene_reads_EDA",
                       title = "Exploratory Data Analysis",
                       h2("EDA Tab"),
                       textOutput("gene_reads_EDA_UI"))
  )
)

## Server ---------------------------------------------------------------------- 
server <- function(input, output, session) {
  ## Nav inside gene_reads ---------------------------------------------------
  observe(
    print(input$gene_reads)
  )
  observeEvent(input$to_QC, 
               updateTabsetPanel(session, "gene_reads", 
                                 selected = "gene_reads_QC"))
  observeEvent(input$to_preview,
               updateTabsetPanel(session = session,
                                 inputId = "gene_reads",
                                 selected = "gene_reads_preview"))
  observeEvent(input$to_EDA,
               updateTabsetPanel(session = session,
                                 inputId = "gene_reads",
                                 selected = "gene_reads_EDA"))
  
  # UI
  output$gene_reads_preview_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_QC_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_EDA_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
}

shinyApp(ui = ui, server = server)

Example 2: Updating a tabsetPanel via external actionButton with yonder. The value of input$gene_reads is NOT updated when the actionButton is clicked, despite changing the tab. This is the exact same app, but uncommented the columns statement to force yonder to load.

## Imports ---------------------------------------------------------------------
library("shiny")
# UI & Bootstrap 4
library('yonder')

ui <- fluidPage(
  title = "actionButton",
  columns(
    column(width = 12,
           h2("action buttons"))
  ),
  tabsetPanel(id = "gene_reads",
              tabPanel(id = "gene_reads_preview",
                       value = "gene_reads_preview",
                       title = "Gene Reads Preview",
                       h2("Preview Tab"),
                       textOutput("gene_reads_preview_UI"),
                       actionButton("to_QC",
                                    "go to QC tab")
              ),
              tabPanel(id = "gene_reads_QC",
                       value = "gene_reads_QC",
                       title = "Gene Reads Quality Control",
                       h2("QC Tab"),
                       textOutput("gene_reads_QC_UI"),
                       actionButton("to_preview",
                                    "go to preview tab"),
                       actionButton("to_EDA",
                                    "go to eda tab")),
              tabPanel(id = "gene_reads_EDA",
                       value = "gene_reads_EDA",
                       title = "Exploratory Data Analysis",
                       h2("EDA Tab"),
                       textOutput("gene_reads_EDA_UI"))
  )
)

## Server ---------------------------------------------------------------------- 
server <- function(input, output, session) {
  ## Nav inside gene_reads ---------------------------------------------------
  observe(
    print(input$gene_reads)
  )
  observeEvent(input$to_QC, 
               updateTabsetPanel(session, "gene_reads", 
                                 selected = "gene_reads_QC"))
  observeEvent(input$to_preview,
               updateTabsetPanel(session = session,
                                 inputId = "gene_reads",
                                 selected = "gene_reads_preview"))
  observeEvent(input$to_EDA,
               updateTabsetPanel(session = session,
                                 inputId = "gene_reads",
                                 selected = "gene_reads_EDA"))
  
  # UI
  output$gene_reads_preview_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_QC_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_EDA_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
}

shinyApp(ui = ui, server = server)

Example 3: Updating a navInput via external actionButton or buttonInput with yonder. I seem to recall that in the documentation it used to say to use navInput / navContent and buttonInput instead of actionButton. This is the same app, but changed the tabsetPanel to navInput / navPane and actionButton to buttonInput. As with example 2, The value of input$gene_reads is NOT updated when the button is clicked, despite changing the tab. It does update when using the navInput menu, though.

## Imports ---------------------------------------------------------------------
library("shiny")
# UI & Bootstrap 4
library('yonder')

ui <- fluidPage(
  title = "actionButton",
  columns(
    column(width = 12,
           h2("action buttons"))
  ),
  navInput(id = "gene_reads",
           choices = c(
             "Preview",
             "QC",
             "EDA"
           ),
           values = c(
             "gene_reads_preview",
             "gene_reads_QC",
             "gene_reads_EDA"       
           )
  ),
  navContent(
    navPane(id = "gene_reads_preview",
            h2("Preview Tab"),
            textOutput("gene_reads_preview_UI"),
            buttonInput(id = "to_QC",
                        label = "go to QC tab")
    ),
    navPane(id = "gene_reads_QC",
            h2("QC Tab"),
            textOutput("gene_reads_QC_UI"),
            buttonInput(id = "to_preview",
                        label = "go to preview tab"),
            buttonInput(id = "to_EDA",
                        label = "go to eda tab")
    ),
    navPane(id = "gene_reads_EDA",
            h2("EDA Tab"),
            textOutput("gene_reads_EDA_UI"))
  )
)

## Server ---------------------------------------------------------------------- 
server <- function(input, output, session) {
  ## Nav inside gene_reads ---------------------------------------------------
  observe(
    print(input$gene_reads)
  )
  observeEvent(input$gene_reads, {
    showNavPane(input$gene_reads)
  })
  
  observeEvent(input$to_QC, 
               showNavPane("gene_reads_QC",
                           session = session))
  observeEvent(input$to_preview, 
               showNavPane("gene_reads_preview",
                           session = session))
  observeEvent(input$to_EDA, 
               showNavPane("gene_reads_EDA",
                           session = session))
  
  # UI
  output$gene_reads_preview_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_QC_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
  output$gene_reads_EDA_UI <- renderText({
    paste("The value of input$gene_reads is", input$gene_reads)
  })
}

shinyApp(ui = ui, server = server)

Is this expected? Is there any workaround? I have looked at the documentation extensively (including the previous releases) but cannot find anything about it.

Again, thank you very much for your work.

@gabrifc gabrifc closed this as completed Nov 23, 2019
@gabrifc
Copy link
Author

gabrifc commented Nov 23, 2019

I still don't know how to do that or if there any solution but I've found other open issues that mention it, as #166 , that I did not see when posting.

@gabrifc gabrifc reopened this Nov 23, 2019
@gabrifc gabrifc closed this as completed Nov 23, 2019
@nteetor
Copy link
Owner

nteetor commented Nov 26, 2019

Hello @gabrifc, I am glad to hear yonder's been of use to you.

The first issue is a conflict between bootstrap 3 and 4. In your first app there are no yonder components, so shiny's bootstrap 3 resources are loaded. In the second and third examples including columns(. . .) includes yonder's bootstrap 4 resources. To avoid conflicts yonder replaces shiny's bootstrap resources rather than load both 3 and 4. So, using shiny's default tab sets based on bs3 would not work. The third example uses yonder's nav components and looks nearly good to go.

Yonder was designed to allow any observer to hide or show nav panes. You are doing exactly this by using a nav input and action buttons to toggle between nav panes. However, showing or hiding a nav pane has no reverse propagation effect. Instead, any observers must update any additional inputs affecting the nav panes. So, in your third example the button input observers must update the selected value of the nav input.

Here are the modified observers,

observeEvent(input$to_QC, {
  updateNavInput(id = "gene_reads", selected = "gene_reads_QC")
  showNavPane("gene_reads_QC")
})

observeEvent(input$to_preview, {
  updateNavInput(id = "gene_reads", selected = "gene_reads_preview")
  showNavPane("gene_reads_preview")
})

observeEvent(input$to_EDA, {
  updateNavInput(id = "gene_reads", selected = "gene_reads_EDA")
  showNavPane("gene_reads_EDA")
})

Did I leave anything out or explain anything confusingly? The yonder approach is more verbose at times. As you may have seen in #166 I am working to eliminate some of this verbosity. In version 1.0.0 you will be able to assign actions to a reactive input, such as show a nav pane. With these actions you will no longer need the calls to showNavPane() seen above. I am also exploring back propagation as part of showing or hiding nav panes. If possible, showing a nav pane P would automatically update the selected value(s) of any input component(s) assigned a show/hide nav action. That would be the catch. For an input to be updated the input must have an associated action to show pane P. Hiding may prove difficult, there's plenty more to come.

I hope this answers your current questions and if you have any new questions or clarifications on this subject feel free to re-open this issue. If anything new came up feel free to open another issue.

@gabrifc
Copy link
Author

gabrifc commented Nov 26, 2019

Hi,

To be honest, I don't really understand why I did not use the updateNavInput together with the showNavPane. I think that I used to update tje input without showing the pane and deemed that it would not work. I ended up hacking a NavInput menu with repeated tab links which I styled with conditionals, and moved to another part of the app, but will go back to this.

Thank you very much for the detailed and careful response. Everything makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants