简体   繁体   English

闪亮模块内的可编辑 DT

[英]editable DT inside shiny module

I would like to have an editable DT inside a shiny module.我想在闪亮的模块中有一个可编辑的 DT。 When I change a value in the DT, then the table updates and it is empty with the message inside the datatable:当我更改 DT 中的值时,表会更新,并且数据表中的消息为空:

"No matching records found" “没有找到匹配的记录”

My code is as follows:我的代码如下:

Modules:模块:

modDtUi <- function(id){ # UI module
  ns = NS(id)
  DT::dataTableOutput(ns('x1'))
} 


modDt <-  function(input, output, session, data){ # Server module

  x <- data
  output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE)

  proxy <- dataTableProxy('x1', session = session)

  observeEvent(input$x1_cell_edit, {
    info = input$x1_cell_edit
    str(info)
    print(info)
    i = info$row
    j = info$col
    v = info$value
    x[i, j] <<- DT::coerceValue(v, x[i, j])
    replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
  })

}

app in flexdashboard: flexdashboard 中的应用程序:

```{r}
modDtUi("editable")
```

```{r}
callModule(modDt,"editable", data = iris)
```

It works well without modules, but I can't get the same results with shiny modules.它在没有模块的情况下运行良好,但我无法使用闪亮的模块获得相同的结果。

Thanks谢谢

This works if you remove rownames = FALSE :如果您删除rownames = FALSE这将起作用:

replaceData(proxy, x, resetPaging = FALSE)#, rownames = FALSE)

If you don't want row names, you have to also set rownames = FALSE in the renderDataTable :如果你不想要行名,你还必须在renderDataTable中设置renderDataTable rownames = FALSE

  output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE, 
                                   rownames = FALSE)

And then you have to add 1 to info$col :然后你必须将1添加到info$col

  observeEvent(input$x1_cell_edit, {
    info = input$x1_cell_edit
    i = info$row
    j = info$col + 1
    v = info$value
    x[i, j] <<- DT::coerceValue(v, x[i, j])
    replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
  })

Full code of the Rmd flexdashboard: Rmd flexdashboard 的完整代码:

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(DT)

modDtUi <- function(id){ # UI module
  ns = NS(id)
  DT::dataTableOutput(ns('x1'))
} 

modDt <-  function(input, output, session, data){ # Server module

  x <- data
  output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE, 
                                   rownames = FALSE)

  proxy <- dataTableProxy('x1', session = session)

  observeEvent(input$x1_cell_edit, {
    info = input$x1_cell_edit
    i = info$row
    j = info$col + 1
    v = info$value
    x[i, j] <<- DT::coerceValue(v, x[i, j])
    replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
  })

}
```

Column {data-width=650}
-----------------------------------------------------------------------

### Editable table

```{r}
modDtUi("editable")
```

```{r}
callModule(modDt, "editable", data = iris)
```

Working from your code, the issue is that the proxy needs the global session (and not the module session).根据您的代码工作,问题在于代理需要全局会话(而不是模块会话)。 See my other answer for an alternative approach.有关替代方法,请参阅我的其他答案。

You can simply pass the global session to the module via an argument.您可以简单地通过参数将全局session传递给模块。

This works:这有效:

library(shiny)
library(DT)

modDtUi <- function(id){ # UI module
  ns = NS(id)
  DT::dataTableOutput(ns('x1'))
}


modDt <-  function(input, output, session, data, globalSession){ # Server module

  x <- data
  output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE)

  proxy <- dataTableProxy('x1', session = globalSession)

  observeEvent(input$x1_cell_edit, {
    info = input$x1_cell_edit
    str(info)
    print(info)
    i = info$row
    j = info$col
    v = info$value
    x[i, j] <<- DT::coerceValue(v, x[i, j])
    replaceData(proxy, x, resetPaging = FALSE)
  })

}

You now have to add the global session in the module call.您现在必须在模块调用中添加全局会话。

With a shiny app:使用闪亮的应用程序:

ui <- fluidPage(
  modDtUi("editable")
)

server <- function(input, output, session) {
  callModule(modDt,"editable", data = iris, globalSession = session)
}

shinyApp(ui = ui, server = server)

With a flexdashboard:使用弹性仪表板:

```{r}
modDtUi("editable")
```

```{r}
callModule(modDt, "editable", data = iris, globalSession = session)
```

If you want to use your updated table in the rest of your app, simply return reactive(x) from your module and capture it when you call the module.如果您想在应用程序的其余部分使用更新后的表,只需从您的模块返回reactive(x)并在调用模块时捕获它。

editable_iris <- callModule(modDt,"editable", data = iris, globalSession = session)

The following gives me an editable table and captures the edited table in a reactive for further use in the application:下面给了我一个可编辑的表格,并在反应中捕获编辑的表格以供在应用程序中进一步使用:

library(shiny)
library(DT)

modDtUi <- function(id){ # UI module
  ns = NS(id)
  DT::dataTableOutput(ns('x1'))
}


modDt <-  function(input, output, session, data){ # Server module

  output$x1 <- DT::renderDataTable(data, selection = 'none', editable = TRUE, server = TRUE)
  proxy <- dataTableProxy('x1', session = session)

  updatedData <- eventReactive(input$x1_cell_edit, {
    info = input$x1_cell_edit
    if (!is.null(info)) {
      str(info)
      data[info$row, info$col] <<- DT::coerceValue(info$value,
                                                   data[info$row, info$col])
    }
    data
  }, ignoreNULL = FALSE)

  return(updatedData)
}

ui <- fluidPage(
  modDtUi("editable"),
  tags$hr(),
  "Proof it works: the table below updates on edit.",
  shiny::tableOutput("proof")
)

server <- function(input, output) {
  editable_dt <- callModule(modDt,"editable", data = iris)

  output$proof <- renderTable({
    editable_dt() %>%
      summarise_if(is.numeric, mean)
  })

}

shinyApp(ui = ui, server = server)

Good Morning早上好

In my code source, i use globalsession but i have the same problem在我的代码源中,我使用 globalsession 但我有同样的问题

library(shiny)
library(DT)
# Data frame df1
# n = 10
# df1 = data.frame(
#   month = month.abb[1:n],
#   YN = rep(c("[Null]", TRUE), times = c(5, 5)),
#   ID = seq_len(n),
#   stringsAsFactors = FALSE
# )
# df1[10,3] <- "[Null]"


modDtUi <- function(id){ # UI module
  ns = NS(id)
  DT::dataTableOutput(ns('x1'))
}


modDt <-  function(input, output, session, df1, globalSession){ # Server module
  
  shinyInput = function(FUN, len, id, value, ...) {
    if (length(value) == 1)
      value <- rep(value, len)
    inputs = character(len)
    for (i in seq_len(len)) {
      inputs[i] = as.character(FUN(paste0(id, i), label = NULL, value = value[i]))
    }
    inputs
  }
  # Function for null value
  nullValue <- function(selectedColumn, df) {
    for (columIndex in selectedColumn) {
      df <- subset(df, df[, columIndex] != "[Null]")
      
    }
    
    df
  }
  
  # obtain the values of inputs
  shinyValue = function(id, len) {
    unlist(lapply(seq_len(len), function(i) {
      value = input[[paste0(id, i)]]
      
      if (is.null(value))
        TRUE
      else
        value
    }))
  }
  
  # Data frame with checkbox in the first row  
  df2 = rbind(ID = shinyInput(
    checkboxInput,
    ncol(df1),
    'ID_',
    value = FALSE,
    width = '1px'
  ),
  df1)
  # Reactive function
  loopData = reactive({
    df2[1, ] <<-
      shinyInput(
        checkboxInput,
        ncol(df1),
        'ID_',
        value = shinyValue('ID_', ncol(df1)),
        width = '1px'
      )
    
    
    checked <- shinyValue('ID_',  ncol(df1))
    
    changed <- which((checked) != 0)
    
    
    df2 = nullValue(changed, df2)
  })
  
  output$x1 = DT::renderDataTable(
    isolate(loopData()),
    filter = "top",
    escape = FALSE,
    selection = 'none',
    options = list(
      dom = 't',
      paging = FALSE,
      ordering = FALSE,
      preDrawCallback = JS(
        'function() { Shiny.unbindAll(this.api().table().node()); }'
      ),
      drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
    )
  )
  
  proxy = dataTableProxy('x1',session=globalSession)
  
  observe({
    replaceData(proxy, loopData())
    print("yes")
  })
  
}
ui <- fluidPage(
  modDtUi("editable")
)

server <- function(input, output, session) {
  callModule(modDt,"editable", df1 = iris[,-5], globalSession = session)
}

shinyApp(ui = ui, server = server)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM