Как добавить раскрывающееся меню к одной строке таблицы, отображаемой с помощью rhandsontable, в то время как другие строки содержат числовые значения?

В приведенном ниже коде R Shiny я пытаюсь добавить раскрывающееся меню только к последней строке таблицы, отображаемой с помощью rhandsontable. Обратите внимание, что таблица может быть расширена пользователем по столбцам с помощью кнопки действия «Добавить серию». Как применить раскрывающийся список только к последней строке таблицы, а не к каждой строке таблицы, как это происходит в настоящее время с приведенным ниже кодом? Я пробовал hot_row, hot_rows и hot_cell, но не уверен, что они это поддерживают. См. поясняющую иллюстрацию ниже. Обратите внимание, что раскрывающийся список также должен отображаться с каждым добавленным столбцом, что в настоящее время работает, но раскрывающиеся списки не должны отображаться в Row_A и Row_B. Раскрывающийся список должен отображаться только в Row_C.

Код:

library(rhandsontable)
library(shiny)

ui <- 
  fluidPage(
    rHandsontableOutput('hottable_1'),
    actionButton("addSeries","Add series")
  ) 

server <- function(input,output,session)({
  seriesTbl_1 <- reactiveVal(
    data.frame(
      'Series 1' = c(1,24,NA),
      row.names = c("Row_A_numeric","Row_B_numeric","Row_C_dropdown")
    )
  ) 
  
  observeEvent(input$hottable_1, {seriesTbl_1(hot_to_r(input$hottable_1))})
  
  output$hottable_1 <- renderRHandsontable({
    tbl <- seriesTbl_1()
    select_option <- c(NA_character_, "Item A", "Item B") 
    rhandsontable(
      tbl,
      rowHeaderWidth = 200, 
      useTypes = TRUE,
      selectCallback = TRUE,
      overflow = "visible"
    ) %>%
      hot_table(id = "hottable_1") %>%
      hot_col(
        col = names(tbl),
        allowInvalid = FALSE,
        type = "dropdown",
        source = select_option
      )
  })
  
  observeEvent(input$addSeries, {
    newSeriesCol_1 <- data.frame(c(1,24,NA)) 
    names(newSeriesCol_1) <- paste("Series", ncol(hot_to_r(input$hottable_1)) + 1)
    seriesTbl_1(cbind(seriesTbl_1(), newSeriesCol_1))
  })
 
  seriesTbl_1_DF <- reactive({seriesTbl_1()})
})

shinyApp(ui, server)

Кажется library(rhandsontable) не поддерживает этот сценарий. Возможно, вы сможете внедрить JS-решение через htmlwidgets::onRender.

ismirsehregal 03.07.2024 09:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
1
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ниже приведено решение с использованием Javascript, которое должно это сделать:

  • Мы используем событие afterInit , где вызывается updateSettings. Это определяет настройки раскрывающегося списка в последней строке.

    instance.updateSettings({
        cells: function(row, col, prop) {
            var cellProperties;
            if (row === 2) {
                cellProperties = {
                    type: 'dropdown',
                    allowInvalid: false,
                    source: select_option,
                };
                return cellProperties;
            }
        }
    });
    

    Обратите внимание, что select_option — это вектор, определенный в R, который я передал ниже объекту rhandsontable, чтобы я мог использовать его в JS, обратившись к instance.params. Однако я обернул код в небольшой setTimeout, потому что кажется, что непосредственно при вызове afterInitparams недоступен. Единственная причина его использования заключается в том, что вы можете определить параметры в R. Если у вас нет проблем с их определением непосредственно в JS, вы можете опустить их ниже. Я также пробовал другие мероприятия, но у меня возникло несколько проблем, которые могут возникнуть из-за shiny окружающей среды.

  • rhandsontable не поддерживается уже несколько лет и, в частности, зависит от handsontable 6.2.2. В более старой версии (см. handontable/handsontable#7689 ) была ошибка, из-за которой заголовки столбцов отображались неправильно после использования updateSettings. По крайней мере, это похоже на проблему, которая была и у меня, поэтому я использовал то, что было зафиксировано, чтобы решить эту проблему в afterRenderer событии:

    function(TD, row, column, prop, value, cellProperties) {
        this.view.wt.wtOverlays.adjustElementsSize();
    }
    

Это будет выглядеть так:

library(rhandsontable)
library(shiny)

ui <- 
  fluidPage(
    rHandsontableOutput('hottable_1'),
    actionButton("addSeries","Add series")
  ) 

server <- function(input,output,session)({
  seriesTbl_1 <- reactiveVal(
    data.frame(
      'Series 1' = c(1,24,NA),
      row.names = c("Row_A_numeric","Row_B_numeric","Row_C_dropdown")
    )
  ) 
  
  observeEvent(input$hottable_1, {seriesTbl_1(hot_to_r(input$hottable_1))})
  
  output$hottable_1 <- renderRHandsontable({
    tbl <- seriesTbl_1()
    rhandsontable(
      tbl,
      rowHeaderWidth = 200, 
      useTypes = TRUE,
      selectCallback = TRUE,
      overflow = "visible",
      select_option = c(NA_character_, "Item A", "Item B"),
      afterInit = htmlwidgets::JS(" 
            function() {
              let instance = this;
              setTimeout(function (){
                select_option = instance.params.select_option
                select_option = select_option instanceof Array ? select_option : [select_option]
          
                instance.updateSettings({
                  cells: function(row, col, prop) {
                           var cellProperties;
                           if (row === 2) {
                             cellProperties = {
                               type: 'dropdown',
                               allowInvalid: false,
                               source: select_option,
                             };
                             return cellProperties;
                           }
                         }       
                });
             }, 50); 
           }"),
      afterRenderer =  htmlwidgets::JS(
        "function (TD, row, column, prop, value, cellProperties) {
            this.view.wt.wtOverlays.adjustElementsSize();
         }
        ")
    ) %>%
      hot_table(id = "hottable_1") 
  })
  
  observeEvent(input$addSeries, {
    newSeriesCol_1 <- data.frame(c(1,24,NA)) 
    names(newSeriesCol_1) <- paste("Series", ncol(hot_to_r(input$hottable_1)) + 1)
    seriesTbl_1(cbind(seriesTbl_1(), newSeriesCol_1))
  })
  
  seriesTbl_1_DF <- reactive({seriesTbl_1()})
})

shinyApp(ui, server)

Привет, Ян. При запуске этого кода я получаю следующее предупреждение: «Предупреждение в colClasses(as.data.frame(out, stringsAsFactors = FALSE), rColClasses,: NA, введенные принуждением». А пока я публикую альтернативное решение в другой ответ. Пожалуйста, дайте мне знать, что вы думаете.

Village.Idyot 03.07.2024 11:25

Простое исправление — в двух местах формирования фрейма данных (seriesTbl_1 <- reactiveVal(data.frame(...)) и newSeriesCol_1 <- data.frame(...)) заменить NA на NA_character_. Это устраняет предупреждения о принуждении.

Village.Idyot 03.07.2024 15:44

Большое спасибо за подсказку. Однако если я это сделаю, числа будут выровнены по левому краю, скорее всего, потому, что они рассматриваются как строки. Я также могу добавить else {cellProperties = {type: 'numeric'}, и тогда единственная разница между текущим решением и новым решением будет заключаться в том, что оно отображает числа, например. «24» вместо «24.00». Что Вы думаете об этом?

Jan 03.07.2024 15:52

Судя по комментарию исмиршерегала, приведенное ниже сообщение работает. Изменения в коде OP заключаются в замене NA в настройке фрейма данных на NA_character_ и добавлении htmlwidgets::onRender(...) к output$hottable:

library(rhandsontable)
library(shiny)

ui <- fluidPage(
  rHandsontableOutput('hottable_1'),
  actionButton("addSeries", "Add series")
)

server <- function(input, output, session) {
  seriesTbl_1 <- reactiveVal(
    data.frame(
      'Series 1' = c(1, 24, NA_character_),
      row.names = c("Row_A_numeric", "Row_B_numeric", "Row_C_dropdown"),
      stringsAsFactors = FALSE
    )
  )
  
  observeEvent(input$hottable_1, {seriesTbl_1(hot_to_r(input$hottable_1))})
  
  output$hottable_1 <- renderRHandsontable({
    tbl <- seriesTbl_1()
    rhandsontable(
      tbl, 
      rowHeaderWidth = 200, 
      useTypes = TRUE, 
      selectCallback = TRUE, 
      overflow = "visible"
      ) %>%
      hot_table(id = "hottable_1") %>%
      htmlwidgets::onRender("
        function(el, x) {
          var hot = this.hot;
          hot.updateSettings({
            cells: function (row, col, prop) {
              var cellProperties = {};
              if (row === 2) {  // Third row
                cellProperties.type = 'dropdown';
                cellProperties.source = ['Item A', 'Item B'];
              } else {  // First two rows
                cellProperties.type = 'numeric';
              }
              return cellProperties;
            }
          });
        }
      ")
  })
  
  observeEvent(input$addSeries, {
    newSeriesCol_1 <- data.frame(
      c(1, 24, NA_character_), 
      stringsAsFactors = FALSE
      ) 
    names(newSeriesCol_1) <- paste("Series", ncol(hot_to_r(input$hottable_1)) + 1)
    seriesTbl_1(cbind(seriesTbl_1(), newSeriesCol_1))
  })
}

shinyApp(ui, server)

Хорошее решение, + 1. Кажется, htmlwidgets::onRender позволяет избежать нескольких проблем, с которыми я столкнулся со своим решением. Как указано в другом комментарии, я думаю, что здесь нет предупреждений о принуждении, потому что числа отображаются в каком-то другом смысле (кажется, есть приведение из-за NA_character_), вместо 24.00, который по умолчанию используется для type: 'numeric', насколько я понимаю, у одного есть 24.

Jan 03.07.2024 15:55

Другие вопросы по теме