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

Внутри блестящего приложения я хочу отключить все кнопки во время работы приложения. У меня есть много кнопок действий, зависимостей и некоторых рендеринов, так что я думаю, что использование brightjs:disable(button) является критически важным и очень нечистым для 40 и более кнопок.

Есть ли простой способ отключить кнопку (или все кнопки / ползунки одновременно), когда блестящее приложение занято, как в условии элемента "loading.." моего примера приложения ниже?

или есть другой способ отключить нажатие всех кнопок или сделать их невидимыми во время выполнения длинных вычислений, обозначенных текстом "loading.."?

В моем примере ниже я хочу отключить кнопку действия, когда приложение занято (отображается текст "loading.."). Я знаю, что для этого примера я мог бы использовать brightjs, но я бы предпочел общее решение, пока приложение занято. Любая помощь действительно приветствуется, я совершенно новичок в html, css и java вещах, так что если кто-то знает решение этой проблемы, краткое объяснение было бы действительно здорово!

Спасибо заранее!

library(shiny)


server <- function(input, output) {
  output$moreControls <- renderUI({if(input$obs!=10001) actionButton("button", "OK!")})
  observeEvent(input$button, {
  output$distPlot <- renderPlot({
    Sys.sleep(5)
    hist(rnorm(isolate(input$obs)), col = 'darkgray', border = 'white')
  })})
}

ui <- fluidPage(tags$head(tags$style(type="text/css", "
                                                                    #loadmessage {
                                     position: fixed;
                                     top: 95%;
                                     left: 0px;
                                     width: 100%;
                                     padding: 5px 0px 5px 0px;
                                     text-align: center;
                                     font-weight: bold;
                                     font-size: 100%;
                                     color: #000000;
                                     background-color: #CCFF66;
                                     z-index: 105;
                                     }
                                     ")),
                conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                                 tags$div("Loading...",id="loadmessage")),
  sidebarLayout( sidebarPanel(

    sliderInput("obs", "Number of observations:", min = 10000, max = 100000, value = 10001,step=1000),
   uiOutput("moreControls")

    ),
    mainPanel(plotOutput("distPlot"))
  )
)

shinyApp(ui = ui, server = server) 

1 ответ

Решение

Я не знаком с простым способом сделать то, что вы описываете, но, конечно, это не означает, что его нет;) Вот небольшой обходной путь, который, я считаю, соответствует вашим требованиям и сохраняет ваш код относительно чистым. Мы можем использовать reactiveValuesToList(input) чтобы получить список наших входных данных, а затем написать функцию, которая отключает или включает их все. Мы также можем решить только переключить button входы путем поднабора списка на основе атрибутов.

Рабочий пример ниже, надеюсь, это поможет!



library(shiny)
library(shinyjs)

ui <- fluidPage(
  h3('Disable all inputs while running'),
  actionButton('btn_all_inputs','Run long process'),
  h3('Disable only buttons while running'),
  actionButton('btn_only_buttons','Run long process'),
  hr(),
  h3('Inputs'),
  textInput('text1', 'Text1',"my text:"),
  actionButton('btn1','Button 1'),
  actionButton('btn2','Button 2'),
  actionButton('btn3','Button 3'),
  sliderInput('slid3','Slider 1',min=0,max=1,value=0.5),
  useShinyjs()
)


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

  # Function to toggle input elements. 
  # input_list: List of inputs, reactiveValuesToList(input)
  # enable_inputs: Enable or disable inputs?
  # Only buttons: Toggle all inputs, or only buttons?
  toggle_inputs <- function(input_list,enable_inputs=T,only_buttons=FALSE)
  {
    # Subset if only_buttons is TRUE.
    if(only_buttons){
      buttons <- which(sapply(input_list,function(x) {any(grepl('Button',attr(x,"class")))}))
      input_list = input_list[buttons]
    }

    # Toggle elements
    for(x in names(input_list))
      if(enable_inputs){
        shinyjs::enable(x)} else {
          shinyjs::disable(x) }
  }

  observeEvent(input$btn_all_inputs,{
    input_list <- reactiveValuesToList(input)
    toggle_inputs(input_list,F,F)
    Sys.sleep(5)
    toggle_inputs(input_list,T,F)
  })

  observeEvent(input$btn_only_buttons,{
    input_list <- reactiveValuesToList(input)
    toggle_inputs(input_list,F,T)
    Sys.sleep(5)
    toggle_inputs(input_list,T,T)
  })
}

shinyApp(ui = ui, server = server)

Альтернативное решение

Это решение использует пользовательские JavaScript включить / отключить все входы в зависимости от того, занят Shiny или нет. Таким образом, это будет отключать ваши входы каждый раз, когда Shiny занят. Теперь я настроил сценарий на отключение всех кнопок, но вы можете легко расширить его, добавив дополнительные параметры в document.getElementsByTagName(), Надеюсь, это ближе к тому, что вы имели в виду.

library(shiny)

ui <- fluidPage(
  h3('Disable buttons while running'),
  actionButton('btn_run','Run long process'),
  hr(),
  h3('Inputs'),
  textInput('text1', 'Text1',"my text:"),
  actionButton('btn1','Button 1'),
  sliderInput('slid3','Slider 1',min=0,max=1,value=0.5),
  includeScript('script.js')
)

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

  observeEvent(input$btn_run,{
    Sys.sleep(5)
  })
}

shinyApp(ui = ui, server = server)

script.js

$(document).on("shiny:busy", function() {
  var inputs = document.getElementsByTagName("button");
  console.log(inputs);
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = true;
}
});

$(document).on("shiny:idle", function() {
  var inputs = document.getElementsByTagName("button");
  console.log(inputs);
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = false;
}
});
Другие вопросы по тегам