R Shiny - Редактирование таблицы данных внутри динамически созданного bsModal - PullRequest
0 голосов
/ 04 марта 2019

Приложение ниже содержит actionButton Add data, который вставляет элемент пользовательского интерфейса при каждом нажатии.Каждый элемент пользовательского интерфейса представляет собой блок, который содержит один selectInput Select data и actionButton Edit, который открывает модальное окно при нажатии.

Каждый модал содержит:

  1. Таблица данных с двумя столбцами: Parameter и Value (этот столбец редактируемый).
  2. actionButton Apply, который применяет любые изменения, внесенные в столбец Value.

Когда пользователь выбирает набор данных внутри поля x, реактивное значение создается для хранениясоответствующие параметры в data.frame x_paramset (где x - это идентификатор поля, вставленного через insertUI) и добавьте столбец val, который имеет то же значение, что и default (см. список в верхней части кода ниже).Затем я использую renderDataTable, чтобы добавить столбец Value (который содержит numericInput) - эта таблица данных отображается внутри модального поля.

Чтобы обновить data.frame, чтобы применить любые изменения, которые пользователь, возможно, сделал в модальном порядке, я использую Наблюдение за событием, которое прослушивает кнопку Apply и обновляет столбец val в data.frame x_paramset со значениями внутри числовых входов в столбце Value.

Вот приложение (bsModal закомментирован и заменен блестящимWidgets :: dropdownButton):

library(shiny)
library(shinydashboard)
library(shinyjs)
library(shinyWidgets)
library(DT)
library(tidyverse)

all = list(p1 = list(a = list(id = "a", default = 10)), 
           p2 = list(x = list(id = "x", default = 20)))

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

ui<-fluidPage(shinyjs::useShinyjs(), 

              tags$head(
                tags$script("
                            $(document).on('click', '.dropdown-shinyWidgets li button', function () {
                            $(this).blur()
                            Shiny.onInputChange('lastClickId',this.id)
                            Shiny.onInputChange('lastClick',Math.random())
                            });                       

                            ")
                ),

              box(title = "Add data", 
                  column(width = 12,
                         fluidRow(
                           tags$div(id = 'add')
                         ),
                         fluidRow(
                           actionButton("addbox", "Add data")
                         ))
                  )
              )

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

server <- function(input, output, session) {

  rvals = reactiveValues()

  getInputs <- function(pattern){
    reactives <- names(reactiveValuesToList(input))
    name = reactives[grep(pattern,reactives)]
    }

  observeEvent(input$addbox, {
    lr = paste0('box', input$addbox)
    insertUI(
      selector = '#add',
      ui = tags$div(id = lr,
                    box(title = lr,

                        selectizeInput(lr, "Choose data:", choices = names(all)), 

                        shinyWidgets::dropdownButton(inputId = paste0(lr, "_settings"), 
                                       circle = F, status = "success", icon = icon("gear"), width = "1000px",
                                       tooltip = tooltipOptions(title = "Click to edit"),

                                       tags$h4(paste0("Edit settings for Learner", lr)),
                                       hr(),
                                       DT::dataTableOutput( paste0(lr, "_paramdt") ), 
                                       bsButton(paste0(lr, "_apply"), "Apply")  
                        ) # end dropdownButton

                        )

      ) #end tags$div
    ) # end inserUI


    # create reactive dataset
    rvals[[ paste0(lr, "_paramset") ]] <- reactive({

      do.call(rbind, all[[ input[[lr]] ]]) %>% 
        cbind(., lr) %>%
        as.data.frame %>%
        mutate(val = default) 

    }) # end reactive


    # render DT in modal
    output[[ paste0(lr, "_paramdt") ]] <- renderDataTable({ 

      DT <- rvals[[ paste0(lr, "_paramset") ]]() %>% 
        mutate( 
          Parameter = id, 
          Value = as.character(numericInput(paste0(lr,"value",id), label = NULL, value = default))) %>%  
        select(Parameter:Value)

      datatable(DT, 
                selection = 'none', 
                #server = F,
                escape = F,
                options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                               drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } '))) 

    }) # end renderDT


    # Apply changes
    observeEvent(input$lastClick, {

      # replace old values with new 
      rvals[[ paste0(lr, "_paramset") ]](rvals[[ paste0(lr, "_paramset") ]]() %>%
                                           mutate(
                                             val = input$box1valuea
                                             )
                                           )
    }) # end apply changes observeEvent

  }) #end observeEvent
}

shinyApp(ui=ui, server=server)

Я сталкиваюсь с ошибками при попытке выполнить следующее:

  1. Add data >> Edit >> make some change to numericInput >> Apply - это сбрасывает numericInput внутри модального режима к его значению по умолчанию, тогда как я хотел бы, чтобы указанное пользователем значение сохранялось при применении изменений или закрытиимодальное.
  2. Приложение вылетает при попытке: Add data >> Edit >> Apply >> close modal >> Add data ИЛИ Дважды нажмите Add data, а затем нажмите Edit в любом из полей.

Я не уверен, где мойлогика сервера не работает.Я знаю, что Shiny не поддерживает модалы «постоянного использования» (https://github.com/rstudio/shiny/issues/1590), но мне было интересно, был ли обходной путь? Я также не уверен, что внутри insertUI observeEvent вызывает сбой приложения вслучаи, описанные выше. Любая помощь, которую вы можете предложить, будет принята с благодарностью!

...