R使用purrr::map动态生成按钮的Shiny模块--如何动态创建观察者来使用这些按钮输入

bakd9h0s  于 2022-12-05  发布在  其他
关注(0)|答案(1)|浏览(140)

我对使用purrr进行函数式编程还是个新手。purrr中可能有一个很好的解决方案。我生成UI按钮,其命名空间ID与 Dataframe 中的记录ID相同。我为每个按钮生成一个观察器。我不知道如何使用按钮单击事件。理想情况下,我希望按钮点击返回相应的记录,以便在其他地方获取。到目前为止,我一直在尝试提取按钮被点击时的id。我动态创建的observeEvents,所以没有办法提前知道按钮ID...我的意思是,我可以在HTML中看到它,但我需要以某种方式返回它,这样我就可以对相应的 Dataframe 记录进行操作。我的简化的可重复应用程序如下所示。在Map中()函数中生成observeEvents,我尝试将各种内容打印到控制台以获取按钮ID。
““this.id”“”“”
在actionButton中。这在一个Shiny应用程序中有效,因为“thisClick”是input中的一个对象。但是在模块上下文中,它不会被创建,或者被销毁。非常感谢任何帮助!
报告代码:

library(shiny)
library(tidyverse)
meals <- data.frame(
MEAL_ID = c(1,2,3,4,5,6),
MEAL_TYPE = c('Breakfast','Breakfast','Lunch','Lunch','Dinner','Dinner'),
MEAL = c('Lox and Bagels','Eggs to Order', 'Pita Sandwiches', 'Chicken Cesar Wraps', 'Lasagna','Steak Dinner'),
DESCRIPTION = c('Delicious lox and bagels.',
                'Eggs with potatoes and fruit',
                'Pita with cold cuts and cookies',
                'Chicken cesar salad in tortillas',
                'Dutch overn lasagna with salad and breadsticks.',
                'Steak with potatoes and salad.')
)
mealCard <- function(session,id, ttl, subttl, desc){
ns <- session$ns
div(id = ns(id), class='card',
    div(class='card-body',
        h5(class='card-title', ttl),
        h6(class='card-subtitle mb-2 text-muted', subttl),
        p(class='card-text', desc),
        actionButton(inputId = ns(paste0('add-',id)),label = 'Add',onclick =
                         "Shiny.onInputChange('thisClick1',this.id)")
    )
)
}

testUI <- function(id) {
ns <- NS(id)
tagList(
  actionButton(ns('dummy'),'Dummy', onclick =
                   "Shiny.onInputChange('thisClick2',this.id)"),
  uiOutput(ns('test')),
  )
}

testServer <- function(id,data) {
moduleServer(id, function(input, output, session) {
    meals <- data
  
    output$test <- renderUI({
        #browser()
        ids <- meals %>% pull(MEAL_ID)
        addButtonIDs <- meals %>% pull(MEAL_ID) %>% paste0('add-',.)
    
        #Make card button observers -- Problem Area
        map(addButtonIDs, ~ observeEvent(input[[.x]],{
            print(input$thisClick1) # Returns null -- this Shiny.onInputChange thing works if not in a module
            print(input[[.x]]) # Button attributes but no ID
            print(addButtonIDs[input[[.x]]]) # This is subsetting by the number of times the button has been clicked
            # id <- gsub('add-','',(input$thisClick)) -- this Shiny.onInputChange thing works if not in a module
            # print(meals %>% filter(MEAL_ID == id)) -- this Shiny.onInputChange thing works if not in a module
            # Need to be able to use the action buttons to do stuff!!
            })
        )
      
        #Make cards
        map(ids, ~ mealCard(session,meals[.,1],meals[.,3],NULL,meals[.,4])) 
    })
  
    observeEvent(input$dummy,{
        #browser()
        print(input$thisClick2) # Returns null -- this Shiny.onInputChange thing works if not in a module
    })
})
}

ui <- fluidPage(
testUI('test1')
)

server <- function(input, output, session) {
testServer('test1', data = meals)
}

shinyApp(ui, server)
e3bfsja2

e3bfsja21#

我不确定您想要通过单击操作按钮来执行哪种操作,但是使用reactiveValues()可以帮助记录按钮被单击的次数。使用下面的解决方案,您应该也能够触发其他操作。

library(shiny)
library(tidyverse)

meals <- data.frame(
  MEAL_ID = c(1,2,3,4,5,6),
  MEAL_TYPE = c('Breakfast','Breakfast','Lunch','Lunch','Dinner','Dinner'),
  MEAL = c('Lox and Bagels','Eggs to Order', 'Pita Sandwiches', 'Chicken Cesar Wraps', 'Lasagna','Steak Dinner'),
  DESCRIPTION = c('Delicious lox and bagels.',
                  'Eggs with potatoes and fruit',
                  'Pita with cold cuts and cookies',
                  'Chicken cesar salad in tortillas',
                  'Dutch overn lasagna with salad and breadsticks.',
                  'Steak with potatoes and salad.')
)

mealCard <- function(session, id, ttl, subttl, desc){
  ns <- session$ns
  div(id = ns(id), class='card',
      div(class='card-body',
          h5(class='card-title', ttl),
          h6(class='card-subtitle mb-2 text-muted', subttl),
          p(class='card-text', desc),
          actionButton(inputId = ns(paste0('add-',id)),
                       label = 'Add'# ,
                       # onclick = "Shiny.onInputChange('thisClick1',this.id)")
          )
      )
  )
}

testUI <- function(id) {
  ns <- NS(id)
  tagList(
    actionButton(ns('dummy'),'Dummy', onclick =
                   "Shiny.onInputChange('thisClick2',this.id)"),
    uiOutput(ns('test')),
  )
}

testServer <- function(id,data) {
  moduleServer(id, function(input, output, session) {
    
    # new: reactiveValues (a list)
    r <- reactiveValues()
    
    meals <- data
    
    output$test <- renderUI({
      #browser()
      ids <- meals %>% pull(MEAL_ID)
      addButtonIDs <- meals %>% pull(MEAL_ID) %>% paste0('add-',.)
      
      #Make card button observers -- Problem Area
      map(addButtonIDs, ~ observeEvent(input[[.x]],{
        # if sub-list is empty set it to one, otherwise take value and add 1
        if ( is.null(r[[.x]])) r[[.x]] <- 1L
        if (!is.null(r[[.x]])) r[[.x]] <- r[[.x]] + 1L
        
        print(input[[paste0("add-", id)]]) # Returns null -- this Shiny.onInputChange thing works if not in a module
        print(input[[.x]]) # Button attributes but no ID
        
      })
      )
      
      #Make cards
      map(ids, ~ mealCard(session, meals[.,1], meals[.,3], NULL, meals[.,4])) 
    })
    
    observeEvent(input$dummy,{
      #browser()
      print(input$thisClick2) # Returns null -- this Shiny.onInputChange thing works if not in a module
    })
  })
}

ui <- fluidPage(
  testUI('test1')
)

server <- function(input, output, session) {
  testServer('test1', data = meals)
}

shinyApp(ui, server)

相关问题