Как условно деактивировать или удалить элементы выбора в контекстном меню rhandsontable?

При запуске приведенного ниже упрощенного кода пользователь может добавлять или удалять строки таблицы, щелкнув правой кнопкой мыши строку, которая через контекстное меню пакета rhandsontable генерирует всплывающее окно с выбором действий. В коде вы можете увидеть, как я использовал функцию onRender(...) и JavaScript, чтобы отключить удаление строк, когда в таблице только 1 строка. Это работает.

Однако я также хотел бы либо деактивировать, либо удалить (в зависимости от того, что проще) выбор «Вставить строку выше», когда пользователь обращается к контекстному меню из первой строки таблицы. Когда пользователь обращается к контекстному меню из любой строки таблицы, кроме первой, функция «Вставить строку выше» должна работать. По сути, мне никогда не нужна пустая верхняя строка. Есть идеи, как это сделать?

Я просмотрел список хуков handsontable и не смог найти эквивалента «beforeAddRow» или тому подобного.

library(shiny)
library(rhandsontable)
library(htmlwidgets)

ui <- fluidPage(
  br(),
  rHandsontableOutput("simple_table")
)

server <- function(input, output) {
  output$simple_table <- renderRHandsontable({
    rhandsontable(data.frame(Value = numeric(1)), contextMenu = TRUE, rowHeaders = TRUE) %>%
      hot_cols(colWidths = 100, type = "numeric") %>%
      # Below prevents row deletion when there is only 1 row in table
      onRender(
        c(
          "function(el, x) {",
          "  var hot = this.hot;",
          "  Handsontable.hooks.add('beforeRemoveRow', function(index, amount){",
          "    var nrows = hot.countRows();",
          "    if (nrows === 1) {",
          "      return false;",
          "    }",
          "  }, hot);",
          "}"
        )
      )
  })
}

shinyApp(ui = ui, server = server)
Basically, I never want a top row that is blank. Разве вы не получите то же самое, если строк несколько, а пользователь выбирает верхнюю и нажимает «Вставить строку выше»?
Jan 21.07.2024 19:33

Поправьте Ян, если есть несколько строк, пользователю не должно быть разрешено добавлять строку выше верхней строки. Спасибо, что обдумали это!

Village.Idyot 21.07.2024 20:51
Поведение ключевого слова "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) для оценки ваших знаний,...
2
2
54
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Я думаю, что лучший вариант — удалить ненужные элементы из контекстного меню, потому что в противном случае пользователя может сбить с толку, почему при нажатии на некоторые элементы ничего не происходит. Вот решение, которое не требует кастомизации Javascript. Здесь я рассматриваю ситуацию, когда вы хотите, чтобы «Вставить строку выше» и «Удалить строку» не были видны, если в таблице есть только одна строка.

Идея состоит в том, что внутри renderRHandsontable у нас также есть задание rhot$x$contextMenu <- ContextMenuItems(), где ContextMenuItems — это reactive, содержащее пункты меню, которые мы обновляем внутри observeEvent на таблице. Внутри этого observeEvent мы различаем регистр nrow() == 1 и nrow() > 1 и устанавливаем элементы соответственно.

library(shiny)
library(rhandsontable)

ui <- fluidPage(
  br(),
  rHandsontableOutput("simple_table")
)

server <- function(input, output) {
  
  ContextMenuItems <- reactiveVal(list(items = c("row_below",
                                                 "---------", "undo", "redo", 
                                                 "---------", "alignment")))
  
  Data <- reactiveVal(data.frame(Value = numeric(1)))
  
  observeEvent(input$simple_table, {
    Data(hot_to_r(input$simple_table))
    nrows_table <- nrow(Data())
    newIt <- ContextMenuItems()
    if (nrows_table == 1) {
      newIt$items <- newIt$items[!(newIt$items %in% c("row_above", "remove_row"))]
    } else if (!(any(c("row_above", "remove_row") %in% newIt$items))) {
      newIt$items <- newIt$items |> append("row_above", 0) |> append("remove_row", 2)
    }
    ContextMenuItems(newIt)
  })
                                  
  output$simple_table <- renderRHandsontable({
    rhot <- rhandsontable(Data(), contextMenu = TRUE, rowHeaders = TRUE) %>%
      hot_cols(colWidths = 100, type = "numeric")
    rhot$x$contextMenu <- ContextMenuItems()
    rhot
  })
}

shinyApp(ui = ui, server = server)

Альтернативный подход, использующий только JavaScript, просто игнорирует любую попытку пользователя вставить строку над первой строкой таблицы. Вот ключевой модифицированный код из раздела сервера:

rhandsontable(data.frame(Value = numeric(1)), contextMenu = TRUE, rowHeaders = TRUE) %>%
  hot_cols(colWidths = 100, type = "numeric") %>%
  onRender(
    c(
      "function(el, x) {",
      "  var hot = this.hot;",
      "  Handsontable.hooks.add('beforeCreateRow', function(index, amount) {",
      "    if (index === 0) {",
      "      return false;",  
      "    }",
      "  });",
      "}"
    )
  )

Свойство disabled для пункта контекстного меню может быть функцией JS, которая имеет доступ к таблице как this. В отличие от подхода с крючком, это немного более сложно определить, где строки будут вставлены или удалены, но это должно привести к улучшению пользовательского опыта.

contextMenuSettings <- list(
  items = list(
    row_above = list(
      # Disable "insert above" if new row would go above the first row.
      disabled = htmlwidgets::JS("function() {
            // Insertion happens above last selection.
            var selected = this.getSelectedRangeLast();
            var topRow = Math.min(selected.from.row, selected.to.row);
            return topRow <= 0;
          }")
    ),
    row_below = list(),
    remove_row = list(
      # Disable "remove row" if all rows would be removed.
      disabled = htmlwidgets::JS("function() {
            // Same row can be selected in multiple ranges.
            var selectedRows = new Set();
            for (var selected of this.getSelectedRange()) {
              var topRow = Math.min(selected.from.row, selected.to.row);
              var bottomRow = Math.max(selected.from.row, selected.to.row);
              for (var row = topRow; row <= bottomRow; row++) {
                selectedRows.add(row);
              }
            }
            return this.countRows() <= selectedRows.size;
          }")
    ),
    sp1 = '---------',
    undo = list(),
    redo = list()
  )
)

Пользовательские настройки необходимо установить после того, как rhandsontable() был установлен. созданный.

library(shiny)
library(rhandsontable)

ui <- fluidPage(
  br(),
  rHandsontableOutput("simple_table")
)

server <- function(input, output) {
  output$simple_table <- renderRHandsontable({
    hot <- rhandsontable(
      data.frame(Value = numeric(1), Value2 = numeric(1)),
      contextMenu = TRUE,
      rowHeaders = TRUE
    )
    
    # Customize context menu.
    hot$x$contextMenu <- contextMenuSettings
    
    hot
  })
}

shinyApp(ui = ui, server = server)

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