闪亮的 DTedit,根据第二个 DTedit table 中的 rows_selected 状态显示或隐藏 insert/new 按钮
Shiny DTedit, show or hide insert/new button based on rows_selected status in second DTedit table
我有两个功能相关的 DTedit 表
当 DT#1 中未选择任何行时,我不希望用户在 DT#2 中获得 Insert/New 按钮
我有 Table1_Results$rows_selected
来测试是否存在选择(长度>0)
我还在 DT#2 中确定了 'New button' 的 id 为 Table2_add
但是没有成功使 Table1_Results$rows_selected
的长度触发 DT#2
的 shinyjs show() 或 hide() 操作
任何人都可以分享一些反应命令来做到这一点!
以下代码不起作用,但说明了我的目标
observe(Table1_Results$rows_selected,{
if (length(Table1_Results$rows_selected)) {
shinyjs::show('Table2_add')
} else {
shinyjs::hide('Table2_add')
}
})
Error in .getReactiveEnvironment()$currentContext() : Operation not
allowed without an active reactive context. (You tried to do something
that can only be done from inside a reactive expression or observer.)
这个使用按钮的手动测试有效
observeEvent(input$showhide, {
toggle('Table2_add')
})
所以确实缺少 Table1_Results$rows_selected
的反应性测试
提前致谢
在下面的代码中:
- 我无法清除观察到的文本输出中的选定行
- 我隐藏新建按钮没有成功
Note: I use DTedit because it allows other features not shown here
AIMs:
1) when no drink is selected, hide the New button for containers
2) manage <table>$rows_selected so that it reflects the current status
library("shiny")
library("shinyjs")
library("DT")
library("DTedit")
server <- function(input, output) {
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection (found 'Drinkdt' by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# manually toggle visibility for New button
observeEvent(input$showhide, {
shinyjs::toggle('Container_add')
})
# clear Drink row selection
observeEvent(input$clearrows, {
Drink_proxy %>% selectRows(NULL)
})
# when no drink is selected, hide the New button for containers
observeEvent(Drink_Results$rows_selected, {
if ( length(Drink_Results$rows_selected) ) {
shinyjs::show('Container_add')
} else {
shinyjs::hide('Container_add')
}
})
# attempt to react on clearing the row-selection
choice <- reactive({
paste0(Drink_Results$rows_selected, " - ", Container_Results$rows_selected)
})
# output current combination
output$choice <- renderText({ as.character(choice()) })
}
ui <- tagList(useShinyjs(),
fluidPage(
shinyFeedback::useShinyFeedback(),
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
)
shinyApp(ui = ui, server = server)
根据源代码,在您的情况下,所选行的反应是 input$Drinkdt_rows_selected
。如果你使用它,你的代码工作正常。试试这个
server <- function(input, output) {
## could not install DTedit. So, made a copy of the function
source("C:\RStuff\GWS\dtedit.R", local=TRUE)
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
name <- "Drink"
# create proxy to clear row selection (found Drinkdt by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# clear Drink row selection
observeEvent(input$clearrows, {
Drink_proxy %>% selectRows(NULL)
shinyjs::hide('Container_add')
})
sel <- reactive({!is.null(input[[paste0(name, 'dt_rows_selected')]])})
observe({
print(sel())
print(input$Drinkdt_rows_selected)
})
# when no drink is selected, hide the New button for containers
observe({
#observeEvent(input[[paste0(name, 'dt_rows_selected')]], {
if ( length(input[[paste0(name, 'dt_rows_selected')]])>0 ) {
shinyjs::show('Container_add')
}else {
shinyjs::hide('Container_add')
}
})
observeEvent(Drink_Results$thedata, {
message(Drink_Results$thedata)
})
observeEvent(input[[paste0(name, 'dt_rows_selected')]], ignoreNULL = FALSE, {
# 'no' (NULL) row will be 'selected' after each edit of the data
message(paste("Selected row:", input[[paste0(name, 'dt_rows_selected')]]))
})
# attempt to react on clearing the row-selection
choice <- reactive({
if (is.null(input[[paste0(name, 'dt_rows_selected')]])) {
paste0("Drink not selected")
}else {
paste0(input[[paste0(name, 'dt_rows_selected')]], " - ", input$Containerdt_rows_selected)
}
})
observeEvent(input$showhide, {
toggle('Container_add')
})
# output current combination
output$choice <- renderText({ choice() })
}
ui <- fluidPage(
shinyFeedback::useShinyFeedback(),
useShinyjs(),
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
shinyApp(ui = ui, server = server)
顺便说一句 - 应该提到原始代码没有使用 DTedit
(v1.0.0) 的 jbryer
版本,它不 return $rows_selected
. DTedit
(v 2.2.3+) 的修改 DavidPatShuiFong
版本 return $rows_selected
.
上面显示的原始代码使用了 observeEvent
,默认情况下,它有 ignoreNULL = TRUE
。这不起作用,因为如果没有选择行,那么 $rows_selected
将 return NULL
.
一个选项是设置 ignoreNULL = FALSE
。不幸的是,这仍然存在 shinyjs::hide
在第一次执行时不起作用的问题,可能是因为 'Container_add' 在第一次执行时还不存在。添加仅执行几次的 invalidateLater
可解决该问题。
library("shiny")
library("shinyjs")
library("DT")
library("DTedit")
server <- function(input, output, session) {
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection (found 'Drinkdt' by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# manually toggle visibility for New button
observeEvent(input$showhide, {
shinyjs::toggle('Container_add')
})
# clear Drink row selection
observeEvent(input$clearrows, ignoreNULL = FALSE, {
Drink_proxy %>% selectRows(NULL)
shinyjs::hide('Container_add')
})
# when no drink is selected, hide the New button for containers
invalidateCount <- reactiveVal(0)
observe({
# need to execute this observe more than once
# (?because 'Container_add' does not actually exist first time?)
if (isolate(invalidateCount()) < 1) {
shiny::invalidateLater(200, session) # 200ms delay
}
isolate(invalidateCount(invalidateCount() + 1))
print(paste0("row selected:", Drink_Results$rows_selected))
if (!is.null(Drink_Results$rows_selected)) {
shinyjs::show('Container_add')
} else {
shinyjs::hide('Container_add')
}
})
}
ui <- tagList(useShinyjs(),
fluidPage(
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
)
shinyApp(ui = ui, server = server)
我有两个功能相关的 DTedit 表
当 DT#1 中未选择任何行时,我不希望用户在 DT#2 中获得 Insert/New 按钮
我有 Table1_Results$rows_selected
来测试是否存在选择(长度>0)
我还在 DT#2 中确定了 'New button' 的 id 为 Table2_add
但是没有成功使 Table1_Results$rows_selected
的长度触发 DT#2
任何人都可以分享一些反应命令来做到这一点!
以下代码不起作用,但说明了我的目标
observe(Table1_Results$rows_selected,{
if (length(Table1_Results$rows_selected)) {
shinyjs::show('Table2_add')
} else {
shinyjs::hide('Table2_add')
}
})
Error in .getReactiveEnvironment()$currentContext() : Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
这个使用按钮的手动测试有效
observeEvent(input$showhide, {
toggle('Table2_add')
})
所以确实缺少 Table1_Results$rows_selected
的反应性测试
提前致谢
在下面的代码中:
- 我无法清除观察到的文本输出中的选定行
- 我隐藏新建按钮没有成功
Note: I use DTedit because it allows other features not shown here
AIMs:
1) when no drink is selected, hide the New button for containers
2) manage <table>$rows_selected so that it reflects the current status
library("shiny")
library("shinyjs")
library("DT")
library("DTedit")
server <- function(input, output) {
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection (found 'Drinkdt' by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# manually toggle visibility for New button
observeEvent(input$showhide, {
shinyjs::toggle('Container_add')
})
# clear Drink row selection
observeEvent(input$clearrows, {
Drink_proxy %>% selectRows(NULL)
})
# when no drink is selected, hide the New button for containers
observeEvent(Drink_Results$rows_selected, {
if ( length(Drink_Results$rows_selected) ) {
shinyjs::show('Container_add')
} else {
shinyjs::hide('Container_add')
}
})
# attempt to react on clearing the row-selection
choice <- reactive({
paste0(Drink_Results$rows_selected, " - ", Container_Results$rows_selected)
})
# output current combination
output$choice <- renderText({ as.character(choice()) })
}
ui <- tagList(useShinyjs(),
fluidPage(
shinyFeedback::useShinyFeedback(),
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
)
shinyApp(ui = ui, server = server)
根据源代码,在您的情况下,所选行的反应是 input$Drinkdt_rows_selected
。如果你使用它,你的代码工作正常。试试这个
server <- function(input, output) {
## could not install DTedit. So, made a copy of the function
source("C:\RStuff\GWS\dtedit.R", local=TRUE)
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
name <- "Drink"
# create proxy to clear row selection (found Drinkdt by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# clear Drink row selection
observeEvent(input$clearrows, {
Drink_proxy %>% selectRows(NULL)
shinyjs::hide('Container_add')
})
sel <- reactive({!is.null(input[[paste0(name, 'dt_rows_selected')]])})
observe({
print(sel())
print(input$Drinkdt_rows_selected)
})
# when no drink is selected, hide the New button for containers
observe({
#observeEvent(input[[paste0(name, 'dt_rows_selected')]], {
if ( length(input[[paste0(name, 'dt_rows_selected')]])>0 ) {
shinyjs::show('Container_add')
}else {
shinyjs::hide('Container_add')
}
})
observeEvent(Drink_Results$thedata, {
message(Drink_Results$thedata)
})
observeEvent(input[[paste0(name, 'dt_rows_selected')]], ignoreNULL = FALSE, {
# 'no' (NULL) row will be 'selected' after each edit of the data
message(paste("Selected row:", input[[paste0(name, 'dt_rows_selected')]]))
})
# attempt to react on clearing the row-selection
choice <- reactive({
if (is.null(input[[paste0(name, 'dt_rows_selected')]])) {
paste0("Drink not selected")
}else {
paste0(input[[paste0(name, 'dt_rows_selected')]], " - ", input$Containerdt_rows_selected)
}
})
observeEvent(input$showhide, {
toggle('Container_add')
})
# output current combination
output$choice <- renderText({ choice() })
}
ui <- fluidPage(
shinyFeedback::useShinyFeedback(),
useShinyjs(),
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
shinyApp(ui = ui, server = server)
顺便说一句 - 应该提到原始代码没有使用 DTedit
(v1.0.0) 的 jbryer
版本,它不 return $rows_selected
. DTedit
(v 2.2.3+) 的修改 DavidPatShuiFong
版本 return $rows_selected
.
上面显示的原始代码使用了 observeEvent
,默认情况下,它有 ignoreNULL = TRUE
。这不起作用,因为如果没有选择行,那么 $rows_selected
将 return NULL
.
一个选项是设置 ignoreNULL = FALSE
。不幸的是,这仍然存在 shinyjs::hide
在第一次执行时不起作用的问题,可能是因为 'Container_add' 在第一次执行时还不存在。添加仅执行几次的 invalidateLater
可解决该问题。
library("shiny")
library("shinyjs")
library("DT")
library("DTedit")
server <- function(input, output, session) {
Drink_Results <- dtedit(
input, output,
name = 'Drink',
thedata = data.frame(
ID = c(1:3),
drink = c('Tea', 'Coffea', 'Water'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection (found 'Drinkdt' by looking in the source)
Drink_proxy <- DT::dataTableProxy('Drinkdt')
Container_Results <- dtedit(
input, output,
name = 'Container',
thedata = data.frame(
ID = c(1:3),
Container = c('Cup', 'Glass', 'Pint'),
stringsAsFactors = FALSE
)
)
# create proxy to clear row selection
Container_proxy <- DT::dataTableProxy('Container')
# manually toggle visibility for New button
observeEvent(input$showhide, {
shinyjs::toggle('Container_add')
})
# clear Drink row selection
observeEvent(input$clearrows, ignoreNULL = FALSE, {
Drink_proxy %>% selectRows(NULL)
shinyjs::hide('Container_add')
})
# when no drink is selected, hide the New button for containers
invalidateCount <- reactiveVal(0)
observe({
# need to execute this observe more than once
# (?because 'Container_add' does not actually exist first time?)
if (isolate(invalidateCount()) < 1) {
shiny::invalidateLater(200, session) # 200ms delay
}
isolate(invalidateCount(invalidateCount() + 1))
print(paste0("row selected:", Drink_Results$rows_selected))
if (!is.null(Drink_Results$rows_selected)) {
shinyjs::show('Container_add')
} else {
shinyjs::hide('Container_add')
}
})
}
ui <- tagList(useShinyjs(),
fluidPage(
h3('What will you drink?'),
uiOutput('Drink'),
# manually clear row selections
actionButton(inputId="clearrows", label="clear selected drink", icon=icon('trash')),
hr(),
h3("What container do you prefer?"),
uiOutput('Container'),
hr(),
# manually hide the New button
actionButton(inputId="showhide", label="toggle New buttons", icon=icon('refresh')),
hr(),
# show current user choices
textOutput('choice'),
)
)
shinyApp(ui = ui, server = server)