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

Redundant reactivity cycle on initialization - insertUI #443

Closed
Polkas opened this issue Jan 12, 2022 · 2 comments · Fixed by #637
Closed

Redundant reactivity cycle on initialization - insertUI #443

Polkas opened this issue Jan 12, 2022 · 2 comments · Fixed by #637
Assignees
Labels
bug Something isn't working core

Comments

@Polkas
Copy link
Contributor

Polkas commented Jan 12, 2022

find out here insightsengineering/teal.modules.general#277 (review)

Objective:
Solve the problem of a redundant reactivity cycle. Most probably the insertUI have to be removed, and replace by other solution. If could not be solved then we need a proper Agile-R (or vignette) subsection, where it is communicated roxygen with explanation.

Summary:
When we use insertUI with immediate option, the UI is visible immediately. However inputs inserted (by insertUI) are not yet added to the client. So we have to wait for the next reactive round. Thus the first reactive round return NULL for all module inputs.
This is a global NEST thing as it comes from the teal::srv_teal function.
Code:

ui = div(ui_tabs_with_filters(session$ns("main_ui"), modules = modules, datasets = datasets_reactive())),

Example why insertUI adding redundant reactivity cycle.

Warning: browser in both apps.

inputs should be available from the first line of code in server, like here (example shiny app):

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Old Faithful Geyser Data"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

        # Show a plot of the generated distribution
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
# inputs are available
browser()
    output$distPlot <- renderPlot({
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

However when we use insertUI (even with immediate option) with shiny inputs then we have to wait for second reactive cycle to see inputs added by insertUI.

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Old Faithful Geyser Data"),

    # Sidebar with a slider input for number of bins
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30),
        div(id = "input22")
        ),
        # Show a plot of the generated distribution
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output, session) {

    insertUI("#input22", immediate = TRUE, ui = textInput(session$ns("xx"), "xx", "xxx"))

    output$distPlot <- renderPlot({
        ## input xx visible in the second reactive cycle.
        browser()
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

# Run the application
shinyApp(ui = ui, server = server)
@Polkas Polkas added the bug Something isn't working label Jan 12, 2022
@Polkas Polkas self-assigned this May 16, 2022
@Polkas
Copy link
Contributor Author

Polkas commented May 17, 2022

DRAFT:

The main problem are splash UI/SRV which are taken from data argument.
The obvious solution will be to have a subpage for login and redirect to the main url, unfortunately there are no subpages in shiny.

Another problem is that each module ui is feed with a reactive datasets, and before for teal.transform::resolve_delayed.

Options:

  • insertUI (current) - first the splash and next the modules
  • data$ui/srv by Modal , what if modal inside the modal
  • renderUI -> if (authenticated) fluidPage else fluidPage
  • both at the same time in the ui , activated with hide/show. The slash srv will return a data which will trigger the start of the main app.

@Polkas
Copy link
Contributor Author

Polkas commented May 17, 2022

New example:

All inputs should be available from the first line of code in the shiny app server. When we use insertUI (even with immediate option) with shiny inputs then we have to wait for a next reactive cycle to see inputs added by insertUI.

The example app will print NULL and "sth" to the R console as in the first cycle the input$sth is empty (NULL).

Notice: commented browser inside the app, n for step by step and c for all waiting steps

library(shiny)

ui <- fluidPage(
  titlePanel("Old Faithful Geyser Data"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      div(id = "input_example")
    ),
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

server <- function(input, output, session) {
  session$onFlush( function() message("Start flush"), once = FALSE)
  session$onFlushed( function() message("End flush"), once = FALSE)
  # immediate inset
  insertUI("#input_example", immediate = TRUE, ui = textInput(session$ns("sth"), "sth", "sth"))

  output$distPlot <- renderPlot({
    # input$sth is not visible in the first cycle.
    # req(input$sth) will solve it
    # browser()
    print(paste("input$bins:", deparse1(input$bins)))
    print(paste("input$sth:", deparse1(input$sth)))
    x <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}

shinyApp(ui = ui, server = server)

# Listening on http://127.0.0.1:7193
# [1] "input$bins: 30L"
# [1] "input$sth: NULL"
# Start flush
# End flush
# [1] "input$bins: 30L"
# [1] "input$sth: \"sth\""
# Start flush
# End flush

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working core
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants