блестящий модуль с обновлениями наблюдаемых событий на основе предыдущих входов - PullRequest
2 голосов
/ 14 июля 2020

У меня есть приложение, которое создает коробки. В каждом поле есть кнопка, запускающая модальное окно. В модальном окне есть входы, которые пользователь изменяет, а затем кнопка, которая запускает действие на основе этих входов (в основном просто загрузка в базу данных). Поскольку у каждого блока своя спецификация, я написал модуль, а затем l oop через список, создав блок для каждого элемента. Это работает нормально.

Однако поток в модальном и наблюдающем событии имеет недостаток: при первом прогоне я получаю желаемые результаты, но во втором случае в том же поле (тот же модуль id) после нажатия модальная кнопка для обновления, она не будет использовать новые входные данные, а будет использовать то, что произошло при первом запуске. Я предполагаю, что это как-то связано с комбинацией пространство имен / наблюдениеEvent, поскольку я мог бы запускать событие с «сохраненным» пространством имен? Нужно ли мне каким-то образом "гриппить sh" пространство имен после каждого обновления? В любом случае, любая помощь приветствуется, поскольку она быстро сбивает с толку все комбинации пространств имен / модулей.

library(shiny)
library(shinyWidgets)

ui <- navbarPage(
  'page', collapsible = TRUE,
  tabPanel("test",
           useSweetAlert(),
           sidebarLayout(
             sidebarPanel(), 
             mainPanel(
               uiOutput('all_products_ui')
               )
           )
  )) # end navbar

server <- shinyServer(function(input, output) {
  list_products <- c(1,2,3,4,5)

  # Now, I will create a UI for all the products
  output$all_products_ui <- renderUI({
    r <- tagList()
    progress_move <- 0
    for(k in 1:length( list_products )){
                     r[[k]] <- ExistingProductUI(id = k, product = list_products[[k]] ) 
    }
    r
  })
  
  # handlers duplicate a call to module depending on the id of ExistingProductUI 
  handlers <- list()
  observe(
    handlers <<- lapply(seq.int(length( list_products )), 
                        function(i) {
                          callModule(ExistingProductUpdate, 
                                     id = i, 
                                     product = list_products[[i]] )
                        })
  )  
  handlers
  
}) # end of server ---- 


# UI module ------------------------------------------------------
ExistingProductUI <- function(id, product){
  ns <- NS(id)
  
  box(title = as.character(p$title), 
      product["title"], 
      footer = tagList(
        actionBttn(
          inputId = ns("change_selected"), label = "change"),
       )
    )
}
# server module ------------------------------------------------------
ExistingProductUpdate <- function(input, output, session, product){
  ns <- session$ns
  
  
  observeEvent(input$change_selected, {
   # when box button is clicked for this product (id)
    # FIRST: show a modal
    showModal(
      modalDialog(
        title = "what do you want to change?",
        tagList(
          radioGroupButtons(inputId = ns("change_selected_choice"), labels = "change x", choices = c(1,2,3,4)),
          sliderInput(ns("change_selected_pct"), "change y:", min = -50, max = 100, value = 0, step = 5)
        ),
        easyClose = TRUE, 
        footer = tagList(
          actionButton(ns("change_selected_submit"), "submit!", icon = icon("check")),
          modalButton("never mind")
        )
      )
    )
    # SECOND: when change_selected_submit is clicked, 
    observeEvent(input$change_selected_submit, {
      
      # do some calculations with product using what I inputed in modal --- 
      # then, update a table ---- 
      functionToUploadThings(product, input$change_selected_choice)
      
    # THIRD: Close with a confirmation
      sendSweetAlert(
        session,
        title = "Success!",
        type = "success",
        btn_labels = "Ok",
        closeOnClickOutside = TRUE,
        width = NULL
      )
    }) 
    
  }) 
}

1 Ответ

1 голос
/ 17 июля 2020

Ниже приведено решение, которое работает. Проблема заключалась в том, что вы вложили свой observeEvent в модуль. Я не совсем уверен, почему это привело к проблемам, некоторые значения обрабатывались некорректно. Однако вам не нужно вкладывать observeEvent, второй также запускается actionButton в модальном окне, когда он сам по себе. Кроме того, я добавил removeModal перед отображением уведомления об успешном завершении:

library(shiny)
library(shinyWidgets)
library(shinydashboard)

ui <- navbarPage(
  'page', collapsible = TRUE,
  tabPanel("test",
           useSweetAlert(),
           sidebarLayout(
             sidebarPanel(), 
             mainPanel(
               uiOutput('all_products_ui')
             )
           )
  )) # end navbar

server <- shinyServer(function(input, output) {
  list_products <- c(1,2,3,4,5)
  
  # Now, I will create a UI for all the products
  output$all_products_ui <- renderUI({
    r <- tagList()
    progress_move <- 0
    for(k in 1:length( list_products )){
      r[[k]] <- ExistingProductUI(id = k, product = list_products[[k]] ) 
    }
    r
  })
  
  # handlers duplicate a call to module depending on the id of ExistingProductUI 
  handlers <- list()
  observe(
    handlers <<- lapply(seq.int(length( list_products )), 
                        function(i) {
                          callModule(ExistingProductUpdate, 
                                     id = i, 
                                     product = list_products[[i]] )
                        })
  )  
  handlers
  
}) # end of server ---- 


# UI module ------------------------------------------------------
ExistingProductUI <- function(id, product){
  ns <- NS(id)
  
  box(title = as.character(product), 
      product, 
      footer = tagList(
        actionBttn(
          inputId = ns("change_selected"), label = "change"),
      )
  )
}
# server module ------------------------------------------------------
ExistingProductUpdate <- function(input, output, session, product){
  ns <- session$ns
  
  
  observeEvent(input$change_selected, {
    # when box button is clicked for this product (id)
    # FIRST: show a modal
    showModal(
      modalDialog(
        title = "what do you want to change?",
        tagList(
          radioGroupButtons(inputId = ns("change_selected_choice"), label = "change x", choices = c(1,2,3,4)),
          sliderInput(ns("change_selected_pct"), "change y:", min = -50, max = 100, value = 0, step = 5)
        ),
        easyClose = TRUE, 
        footer = tagList(
          actionButton(ns("change_selected_submit"), "submit!", icon = icon("check")),
          modalButton("never mind")
        )
      )
    )
  })
  
  # SECOND: when change_selected_submit is clicked, 
  observeEvent(input$change_selected_submit, {
    
    # do some calculations with product using what I inputed in modal --- 
    # then, update a table ---- 
    # functionToUploadThings(product, input$change_selected_choice)
    # THIRD: Close with a confirmation
    removeModal()
    sendSweetAlert(
      session,
      title = "Success!",
      type = "success",
      btn_labels = "Ok",
      closeOnClickOutside = TRUE,
      width = NULL
    )
  }) 
}

shinyApp(ui, server)

Обратите внимание: я внес некоторые изменения, чтобы заставить ваш MWE работать:

  • include library(shinydashboard)
  • p$title и product["title"] на product
  • изменить labels на label в radioGroupButtons
  • закомментировать functionToUploadThings(product, input$change_selected_choice)

Edit

Я все еще не уверен, что происходит при вложении observeEvents. Я сделал небольшой игрушечный пример и поигрался с reactlog. Кажется, что вложенность наблюдателей генерирует нового наблюдателя для button2 каждый раз, когда нажимается button1. Эти наблюдатели не удаляются и ведут к нежелательному поведению. Напротив, при использовании отдельного observeEvents наблюдатель для button2 создается только один раз.

library(shiny)
library(reactlog)

ui <- fluidPage(
  actionButton("button1", "click")
)

server <- function(input, output, session) {
  observeEvent(input$button1, {
    print("from first observer")
    print(input$button2)
    showModal(
      modalDialog(
        title = "what do you want to change?",
        "some text",
        easyClose = TRUE, 
        footer = tagList(
          actionButton("button2", "submit!", icon = icon("check")),
          modalButton("never mind")
        )
      )
    )
    
    # nested observer -> leads to remaining observers
    observeEvent(input$button2, {
      print("from second observer")
      print(input$button2)
      removeModal()
    })
    
    
    
  })
  
  # independent observer -> generates only one observer
  # observeEvent(input$button2, {
  #   print("from second observer")
  #   print(input$button2)
  #   removeModal()
  # })
}

shinyApp(ui, server)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...