闪亮的 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)