在模块化闪亮应用程序中捕获编辑后的数据表输出时出现问题

发布于 2025-01-17 15:48:40 字数 11863 浏览 4 评论 0原文

我有一个闪亮的应用程序,它利用带有下拉菜单的数据表来控制所选列的更新。当我模块化闪亮的应用程序时,我不再能够捕获更新表的结果。我对下拉菜单采用的方法是基于我收到的对之前问题(@ismirsehregal)的回复。

< https://stackoverflow.com/ questions/69959720/edit-datatable-in-shiny-with-dropdown-selection-for-dt-v0-19>

下面我提供了两个版本我的应用程序 nonmod2_appmod2_app。第一个没有模块并且可以按需要工作。第二个是模块化版本,我在输出中得到 NULL。

当用户运行该应用程序时,他们会看到一个“加载数据”按钮,该按钮将汽车数据加载为 cars_df 并创建一个我称为 cars_meta 的新表,其中包含三个值。然后,它创建一个名为 cars_object 的列表,向其中添加 cars_dfcars_meta。然后将其设为反应值cars_reactive

然后,用户会看到一个反应性cars_reactive$cars_meta的可编辑数据表(initTbl),用户可以通过下拉菜单更新两个字段的值。当用户完成更新并选择“提交”按钮时,选择结果将保存为 cars_reactive$cars_meta。我将更新后的 cars_reactive$cars_meta 显示为 verbatimTextOutput,以便人们可以看到它是如何更新的。

在这两个示例中,我将第一类值从“数字”更新为“字符”,然后选择“提交”。在 nonmod2_app 版本中,结果表保存原始值并反映我更新的值。

nonmod_output

mod2_app 版本中,两个可选字段的所有值都为 NULL。

mod1_output

我怀疑它与命名空间有关,但我不知道缺少什么。

这是非模块化版本的用户界面和服务器代码。


#------- LIBRARIES ---------------------

library(dplyr)
library(tidyselect)
library(stringr)
library(purrr)
library(shinyjs)
library(DT)


# ------  UI  ------------------

shiny_ui <- function() {
    fluidPage(
        actionButton("new_data", "Load Data"),
        br(),
        DT::dataTableOutput("main_table"),
        br(),
        actionButton("commit_meta", "Commit"),
        br(),
        verbatimTextOutput("cars_meta")
    )
}




# -------- SERVER  ---------------

shiny_server <- function(input, output, session) {
    
    v <- reactiveValues()
    
    #place holders
    selectInputIDclass <- "class"
    selectInputIDusage <- "usage"
    
    observeEvent(input$new_data, once = TRUE, {

        
        cars_df <- mtcars
        
        #simulate creating meta table
        cars_meta <- dplyr::tibble(variable = names(cars_df), class = sapply(cars_df, class), usage = c("val1", "val2", "val3","val1", "val2", "val3","val1", "val2", "val3","val1", "val2"))
        cars_meta$class <- factor(cars_meta$class,  c("numeric", "character", "factor"))
        cars_meta$usage <- factor(cars_meta$usage,  c("val1", "val2", "val3"))
        
        #simulate creating the cars_object
        cars_object <- list()
        cars_object$cars_df <- cars_df
        cars_object$cars_meta <- cars_meta
        

        #make initTbl
        selectInputIDclass <<- paste0("sel_class", 1:nrow(cars_object$cars_meta))
        selectInputIDusage <<- paste0("sel_usage", 1:nrow(cars_object$cars_meta))
        
        v$initTbl <- dplyr::tibble(
            variable = cars_object$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("character","numeric", "factor"),
                                                                                    selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
            usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"),
                                                                                    selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
        )

        
        v$cars_reactive <- reactive({
            cars_object
        })
    })
    
    
    displayTbl <- reactive({
        dplyr::tibble(
            variable = v$cars_reactive()$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("numeric", "character", "factor"), selected = input[[x]]))}),
            usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"), selected = input[[x]]))})
        )
    })
    
    
    resultTbl <- reactive({
        dplyr::tibble(
            variable = v$cars_reactive()$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){input[[x]]}),
            usage = sapply(selectInputIDusage, function(x){input[[x]]})
        )
    })
    
    
    output$main_table = DT::renderDataTable({
        req(isTruthy(input$new_data))
        DT::datatable(
            v$initTbl, escape = FALSE, selection = 'none', rownames = FALSE,
            options = list(paging = FALSE, ordering = FALSE, scrollx = TRUE, dom = "t",
                           preDrawCallback = DT::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                           drawCallback = DT::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
            )
        )
    }, server = TRUE)
    
    
    main_table_proxy <- DT::dataTableProxy(outputId = "main_table", session = session)
    
    
    observeEvent({sapply(selectInputIDclass, function(x){input[[x]]})}, {
        replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
    }, ignoreInit = TRUE)
    
    
    observeEvent({sapply(selectInputIDusage, function(x){input[[x]]})}, {
        replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
    }, ignoreInit = TRUE)
    
    
    observeEvent(input$commit_meta, {  
        object = v$cars_reactive()
        table = resultTbl()
        object$cars_meta <- table
        v$cars_reactive <- reactive({object})
    })
    
    
    
    
    output$cars_meta <- renderPrint({
        req (input$commit_meta > 0)
        isolate({v$cars_reactive()$cars_meta})
    })
}



# ------- APP ----------

nonmod2_app <- function(...) {
    app <- shiny::shinyApp(
        ui = shiny_ui,
        server = shiny_server
    )
    
    shiny::runApp(app, ...)
}

这是模块化版本的代码。

#------- LIBRARIES ---------------------

library(dplyr)
library(tidyselect)
library(stringr)
library(purrr)
library(shinyjs)
library(DT)



# ------  UI MODULE ------------------

mod_ui <- function(id) {
    fluidPage(
        actionButton(NS(id,"new_data"), "Load Data"),
        br(),
        DT::dataTableOutput(NS(id, 'main_table')),
        br(),
        actionButton(NS(id, "commit_meta"), "Commit"),
        br(),
        verbatimTextOutput(NS(id, "cars_meta"))
    )
}


# -------- SERVER MODULE ---------------

mod_server <- function(id) {
    shiny::moduleServer(id, function(input, output,session){
        
        v <- reactiveValues()
        
        #place holders
        selectInputIDclass <- "class"
        selectInputIDusage <- "usage"
        
        observeEvent(input$new_data, once = TRUE, {
            
            
            cars_df <- mtcars
            
            #simulate creating meta table
            cars_meta <- dplyr::tibble(variable = names(cars_df), class = sapply(cars_df, class), usage = c("val1", "val2", "val3","val1", "val2", "val3","val1", "val2", "val3","val1", "val2"))
            cars_meta$class <- factor(cars_meta$class,  c("numeric", "character", "factor"))
            cars_meta$usage <- factor(cars_meta$usage,  c("val1", "val2", "val3"))
            
            #simulate creating the cars_object
            cars_object <- list()
            cars_object$cars_df <- cars_df
            cars_object$cars_meta <- cars_meta
            
            
            #make initTbl
            selectInputIDclass <<- paste0("sel_class", 1:nrow(cars_object$cars_meta))
            selectInputIDusage <<- paste0("sel_usage", 1:nrow(cars_object$cars_meta))
            
            v$initTbl <- dplyr::tibble(
                variable = cars_object$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("character","numeric", "factor"),
                                                                                        selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
                usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"),
                                                                                        selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
            )
            
            
            v$cars_reactive <- reactive({
                cars_object
            })
        })
        
        
        displayTbl <- reactive({
            dplyr::tibble(
                variable = v$cars_reactive()$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("numeric", "character", "factor"), selected = input[[x]]))}),
                usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"), selected = input[[x]]))})
            )
        })
        
        
        resultTbl <- reactive({
            dplyr::tibble(
                variable = v$cars_reactive()$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){input[[x]]}),
                usage = sapply(selectInputIDusage, function(x){input[[x]]})
            )
        })
        
        
        output$main_table = DT::renderDataTable({
            req(isTruthy(input$new_data))
            DT::datatable(
                v$initTbl, escape = FALSE, selection = 'none', rownames = FALSE,
                options = list(paging = FALSE, ordering = FALSE, scrollx = TRUE, dom = "t",
                               preDrawCallback = DT::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                               drawCallback = DT::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
                )
            )
        }, server = TRUE)
        
        
        main_table_proxy <- DT::dataTableProxy(outputId = "main_table", session = session)
        
        
        observeEvent({sapply(selectInputIDclass, function(x){input[[x]]})}, {
            replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
        }, ignoreInit = TRUE)
        
        
        observeEvent({sapply(selectInputIDusage, function(x){input[[x]]})}, {
            replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
        }, ignoreInit = TRUE)
        
        
        observeEvent(input$commit_meta, {  
            object = v$cars_reactive()
            table = resultTbl()
            object$cars_meta <- table
            v$cars_reactive <- reactive({object})
        })
        
        
        
        
        output$cars_meta <- renderPrint({
            req (input$commit_meta > 0)
            isolate({v$cars_reactive()$cars_meta})
        })
    })
}



# ------- UI SERVER APP ----------

shiny_ui <- function() {
    
    fluidPage(
        mod_ui("data")
    )
    
}


shiny_server <- function(input, output, session) {
    
    sv <- mod_server("data")
    
}



mod2_app <- function(...) {
    app <- shiny::shinyApp(
        ui = shiny_ui,
        server = shiny_server
    )
    
    shiny::runApp(app, ...)
}

非常感谢您的帮助。

I have a shiny app that utilizes a data table with drop down menus to control the updates of select columns. When I modularize the shiny app, I am no longer able to capture the results of the updated table. The approach I am following for the drop down menus is based on a response I received to an earlier question (@ismirsehregal).

< https://stackoverflow.com/questions/69959720/edit-datatable-in-shiny-with-dropdown-selection-for-dt-v0-19>

Below I’ve provided two versions of my app, nonmod2_app and mod2_app. The first is without modules and works as desired. The second is a modularized version and I am getting NULL in the output.

When the User runs the app they are presented with a Load Data button which loads the cars data as cars_df and creates a new table I call cars_meta with three values. It then creates a list called cars_object to which cars_df and cars_meta are added. This is then made a reactive value, cars_reactive.

The User is then presented with a an editable data table (initTbl) of the reactive cars_reactive$cars_meta for which they can update the values of two fields via drop down menus. When the User is done making updates and selects the Commit button, the results of the selections are saved as cars_reactive$cars_meta. I display the updated cars_reactive$cars_meta as verbatimTextOutput so one can see how it was updated.

In both examples, I update the first class value from “numeric” to “character” and select Commit. In the nonmod2_app version the results table holds the original values and reflects the one I updated.

nonmod_output

In the mod2_app version, I get NULL for all values of the two selectable fields.

mod1_output

I suspect it has something to do with namespace, but am at a loss to figure out what is missing.

Here is the ui and server code for the non modularized version.


#------- LIBRARIES ---------------------

library(dplyr)
library(tidyselect)
library(stringr)
library(purrr)
library(shinyjs)
library(DT)


# ------  UI  ------------------

shiny_ui <- function() {
    fluidPage(
        actionButton("new_data", "Load Data"),
        br(),
        DT::dataTableOutput("main_table"),
        br(),
        actionButton("commit_meta", "Commit"),
        br(),
        verbatimTextOutput("cars_meta")
    )
}




# -------- SERVER  ---------------

shiny_server <- function(input, output, session) {
    
    v <- reactiveValues()
    
    #place holders
    selectInputIDclass <- "class"
    selectInputIDusage <- "usage"
    
    observeEvent(input$new_data, once = TRUE, {

        
        cars_df <- mtcars
        
        #simulate creating meta table
        cars_meta <- dplyr::tibble(variable = names(cars_df), class = sapply(cars_df, class), usage = c("val1", "val2", "val3","val1", "val2", "val3","val1", "val2", "val3","val1", "val2"))
        cars_meta$class <- factor(cars_meta$class,  c("numeric", "character", "factor"))
        cars_meta$usage <- factor(cars_meta$usage,  c("val1", "val2", "val3"))
        
        #simulate creating the cars_object
        cars_object <- list()
        cars_object$cars_df <- cars_df
        cars_object$cars_meta <- cars_meta
        

        #make initTbl
        selectInputIDclass <<- paste0("sel_class", 1:nrow(cars_object$cars_meta))
        selectInputIDusage <<- paste0("sel_usage", 1:nrow(cars_object$cars_meta))
        
        v$initTbl <- dplyr::tibble(
            variable = cars_object$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("character","numeric", "factor"),
                                                                                    selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
            usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"),
                                                                                    selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
        )

        
        v$cars_reactive <- reactive({
            cars_object
        })
    })
    
    
    displayTbl <- reactive({
        dplyr::tibble(
            variable = v$cars_reactive()$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("numeric", "character", "factor"), selected = input[[x]]))}),
            usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"), selected = input[[x]]))})
        )
    })
    
    
    resultTbl <- reactive({
        dplyr::tibble(
            variable = v$cars_reactive()$cars_meta$variable,
            class = sapply(selectInputIDclass, function(x){input[[x]]}),
            usage = sapply(selectInputIDusage, function(x){input[[x]]})
        )
    })
    
    
    output$main_table = DT::renderDataTable({
        req(isTruthy(input$new_data))
        DT::datatable(
            v$initTbl, escape = FALSE, selection = 'none', rownames = FALSE,
            options = list(paging = FALSE, ordering = FALSE, scrollx = TRUE, dom = "t",
                           preDrawCallback = DT::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                           drawCallback = DT::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
            )
        )
    }, server = TRUE)
    
    
    main_table_proxy <- DT::dataTableProxy(outputId = "main_table", session = session)
    
    
    observeEvent({sapply(selectInputIDclass, function(x){input[[x]]})}, {
        replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
    }, ignoreInit = TRUE)
    
    
    observeEvent({sapply(selectInputIDusage, function(x){input[[x]]})}, {
        replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
    }, ignoreInit = TRUE)
    
    
    observeEvent(input$commit_meta, {  
        object = v$cars_reactive()
        table = resultTbl()
        object$cars_meta <- table
        v$cars_reactive <- reactive({object})
    })
    
    
    
    
    output$cars_meta <- renderPrint({
        req (input$commit_meta > 0)
        isolate({v$cars_reactive()$cars_meta})
    })
}



# ------- APP ----------

nonmod2_app <- function(...) {
    app <- shiny::shinyApp(
        ui = shiny_ui,
        server = shiny_server
    )
    
    shiny::runApp(app, ...)
}

Here is the code for the modularized version.

#------- LIBRARIES ---------------------

library(dplyr)
library(tidyselect)
library(stringr)
library(purrr)
library(shinyjs)
library(DT)



# ------  UI MODULE ------------------

mod_ui <- function(id) {
    fluidPage(
        actionButton(NS(id,"new_data"), "Load Data"),
        br(),
        DT::dataTableOutput(NS(id, 'main_table')),
        br(),
        actionButton(NS(id, "commit_meta"), "Commit"),
        br(),
        verbatimTextOutput(NS(id, "cars_meta"))
    )
}


# -------- SERVER MODULE ---------------

mod_server <- function(id) {
    shiny::moduleServer(id, function(input, output,session){
        
        v <- reactiveValues()
        
        #place holders
        selectInputIDclass <- "class"
        selectInputIDusage <- "usage"
        
        observeEvent(input$new_data, once = TRUE, {
            
            
            cars_df <- mtcars
            
            #simulate creating meta table
            cars_meta <- dplyr::tibble(variable = names(cars_df), class = sapply(cars_df, class), usage = c("val1", "val2", "val3","val1", "val2", "val3","val1", "val2", "val3","val1", "val2"))
            cars_meta$class <- factor(cars_meta$class,  c("numeric", "character", "factor"))
            cars_meta$usage <- factor(cars_meta$usage,  c("val1", "val2", "val3"))
            
            #simulate creating the cars_object
            cars_object <- list()
            cars_object$cars_df <- cars_df
            cars_object$cars_meta <- cars_meta
            
            
            #make initTbl
            selectInputIDclass <<- paste0("sel_class", 1:nrow(cars_object$cars_meta))
            selectInputIDusage <<- paste0("sel_usage", 1:nrow(cars_object$cars_meta))
            
            v$initTbl <- dplyr::tibble(
                variable = cars_object$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("character","numeric", "factor"),
                                                                                        selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
                usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"),
                                                                                        selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
            )
            
            
            v$cars_reactive <- reactive({
                cars_object
            })
        })
        
        
        displayTbl <- reactive({
            dplyr::tibble(
                variable = v$cars_reactive()$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = x, label = "", choices = c("numeric", "character", "factor"), selected = input[[x]]))}),
                usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = x, label = "", choices = c("val1", "val2", "val3"), selected = input[[x]]))})
            )
        })
        
        
        resultTbl <- reactive({
            dplyr::tibble(
                variable = v$cars_reactive()$cars_meta$variable,
                class = sapply(selectInputIDclass, function(x){input[[x]]}),
                usage = sapply(selectInputIDusage, function(x){input[[x]]})
            )
        })
        
        
        output$main_table = DT::renderDataTable({
            req(isTruthy(input$new_data))
            DT::datatable(
                v$initTbl, escape = FALSE, selection = 'none', rownames = FALSE,
                options = list(paging = FALSE, ordering = FALSE, scrollx = TRUE, dom = "t",
                               preDrawCallback = DT::JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                               drawCallback = DT::JS('function() { Shiny.bindAll(this.api().table().node()); } ')
                )
            )
        }, server = TRUE)
        
        
        main_table_proxy <- DT::dataTableProxy(outputId = "main_table", session = session)
        
        
        observeEvent({sapply(selectInputIDclass, function(x){input[[x]]})}, {
            replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
        }, ignoreInit = TRUE)
        
        
        observeEvent({sapply(selectInputIDusage, function(x){input[[x]]})}, {
            replaceData(proxy = main_table_proxy, data = displayTbl(), rownames = FALSE)
        }, ignoreInit = TRUE)
        
        
        observeEvent(input$commit_meta, {  
            object = v$cars_reactive()
            table = resultTbl()
            object$cars_meta <- table
            v$cars_reactive <- reactive({object})
        })
        
        
        
        
        output$cars_meta <- renderPrint({
            req (input$commit_meta > 0)
            isolate({v$cars_reactive()$cars_meta})
        })
    })
}



# ------- UI SERVER APP ----------

shiny_ui <- function() {
    
    fluidPage(
        mod_ui("data")
    )
    
}


shiny_server <- function(input, output, session) {
    
    sv <- mod_server("data")
    
}



mod2_app <- function(...) {
    app <- shiny::shinyApp(
        ui = shiny_ui,
        server = shiny_server
    )
    
    shiny::runApp(app, ...)
}

Your help is much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

゛清羽墨安 2025-01-24 15:48:40

在您的新 mod_server 中尝试一下,它对我有用。

  ns <- session$ns
  v$initTbl <- dplyr::tibble(
    variable = cars_object$cars_meta$variable,
    class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = ns(x), label = "", choices = c("character","numeric", "factor"),
                                                                            selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
    usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = ns(x), label = "", choices = c("val1", "val2", "val3"),
                                                                            selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
  )

Try this in your new mod_server, it works for me.

  ns <- session$ns
  v$initTbl <- dplyr::tibble(
    variable = cars_object$cars_meta$variable,
    class = sapply(selectInputIDclass, function(x){as.character(selectInput(inputId = ns(x), label = "", choices = c("character","numeric", "factor"),
                                                                            selected = cars_object$cars_meta$class[which(selectInputIDclass == x)]))}),
    usage = sapply(selectInputIDusage, function(x){as.character(selectInput(inputId = ns(x), label = "", choices = c("val1", "val2", "val3"),
                                                                            selected = cars_object$cars_meta$usage[which(selectInputIDusage == x)]))})
  )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文