我正在尝试做一些一点点棘手的事情,希望有人能帮助我。
我想在数据表中添加selectInput
。
如果启动应用程序,则会看到输入col_1
,col_2
..已很好地连接到数据表(可以切换到a,b或c)
但是
如果我更新数据集(从iris
到mtcars
),则输入和数据表之间的连接将丢失。现在,如果您更改selectinput
,则日志不会显示修改。如何保留链接?
我使用shiny.bindAll()
和shiny.unbindAll()
进行了一些测试,但没有成功。
有什么想法吗?
请查看该应用程序
library(shiny)
library(DT)
library(shinyjs)
library(purrr)
ui <- fluidPage(
selectInput("data","choose data",choices = c("iris","mtcars")),
DT::DTOutput("tableau"),
verbatimTextOutput("log")
)
server <- function(input, output, session) {
dataset <- reactive({
switch (input$data,
"iris" = iris,
"mtcars" = mtcars
)
})
output$tableau <- DT::renderDT({
col_names<-
seq_along(dataset()) %>%
map(~selectInput(
inputId = paste0("col_",.x),
label = NULL,
choices = c("a","b","c"))) %>%
map(as.character)
DT::datatable(dataset(),
options = list(ordering = FALSE,
preDrawCallback = JS("function() {
Shiny.unbindAll(this.api().table().node()); }"),
drawCallback = JS("function() { Shiny.bindAll(this.api().table().node());
}")
),
colnames = col_names,
escape = FALSE
)
})
output$log <- renderPrint({
lst <- reactiveValuesToList(input)
lst[order(names(lst))]
})
}
shinyApp(ui, server)
答案 0 :(得分:4)
了解您的挑战:
为了确定您面临的挑战,您必须了解两件事。
selectInput()
只是html代码的包装器。如果您在控制台中输入selectInput("a", "b", "c")
,它将返回:
<div class="form-group shiny-input-container">
<label class="control-label" for="a">b</label>
<div>
<select id="a"><option value="c" selected>c</option></select>
<script type="application/json" data-for="a" data-nonempty="">{}</script>
</div>
</div>
请注意,您正在构建<select id="a">
,这是id="a"
的选择。因此,如果我们假设1)在刷新后是正确的,则您尝试构建另一个具有现有ID的html元素:<select id="a">
。那不行:Can multiple different HTML elements have the same ID if they're different elements?。 (假设我的假设1)成立;))
解决挑战:
乍看之下非常简单:只要确保您使用的ID在创建的html文档中是唯一的即可。
一种非常快捷和肮脏的方法是更换:
inputId = paste0("col_",.x)
,例如:inputId = paste0("col_", 1:nc, "-", sample(1:9999, nc))
。
但是那以后您将很难使用它。
更长的方式:
所以您可以使用某种内存
您可以使用
global <- reactiveValues(oldId = c(), currentId = c())
为此。
一个过滤掉旧的id并提取当前id的想法可能是:
lst <- reactiveValuesToList(input)
lst <- lst[setdiff(names(lst), global$oldId)]
inp <- grepl("col_", names(lst))
names(lst)[inp] <- sapply(sapply(names(lst)[inp], strsplit, "-"), "[", 1)
可重现的示例为:
library(shiny)
library(DT)
library(shinyjs)
library(purrr)
ui <- fluidPage(
selectInput("data","choose data",choices = c("iris","mtcars")),
dataTableOutput("tableau"),
verbatimTextOutput("log")
)
server <- function(input, output, session) {
global <- reactiveValues(oldId = c(), currentId = c())
dataset <- reactive({
switch (input$data,
"iris" = iris,
"mtcars" = mtcars
)
})
output$tableau <- renderDataTable({
isolate({
global$oldId <- c(global$oldId, global$currentId)
nc <- ncol(dataset())
global$currentId <- paste0("col_", 1:nc, "-", sample(setdiff(1:9999, global$oldId), nc))
col_names <-
seq_along(dataset()) %>%
map(~selectInput(
inputId = global$currentId[.x],
label = NULL,
choices = c("a","b","c"))) %>%
map(as.character)
})
DT::datatable(dataset(),
options = list(ordering = FALSE,
preDrawCallback = JS("function() {
Shiny.unbindAll(this.api().table().node()); }"),
drawCallback = JS("function() { Shiny.bindAll(this.api().table().node());
}")
),
colnames = col_names,
escape = FALSE
)
})
output$log <- renderPrint({
lst <- reactiveValuesToList(input)
lst <- lst[setdiff(names(lst), global$oldId)]
inp <- grepl("col_", names(lst))
names(lst)[inp] <- sapply(sapply(names(lst)[inp], strsplit, "-"), "[", 1)
lst[order(names(lst))]
})
}
shinyApp(ui, server)