在Shiny应用程序中实现实时和取消按钮

问题描述 投票:0回答:1

我有这个应用程序,它有 selectinput() 和两个选项 Manual 和 Tiempo Real。

Options Manual:当您选择Manual时,您将选择Fecha Inicio和Fecha Fin,您可以做出两个选择:Lanzar Consulta或Cancelar Consulta。第一个将构建一个包含两列 fecha 和 valor 的数据框,当您想要取消第一个按钮时(例如,您的日期有误),将使用第二个按钮。

Options Tiempo Real:当您选择它时,您有一个materialSwitch(),当您单击第一个按钮(Lanzar Consulta)时,它每五秒刷新一次查询,而Cancelar Consulta按钮将用于停止实时并停用选项刷新materialSwithch()。

而且,我希望当将选项手册更改为 tiempo real 或反之亦然时, tablaResult 的结果是干净的。

所以,我想实现这个条件,但闪亮的应用程序的代码没有得到它。我必须更改选择并实施取消按钮。

library(shiny)
library(shinyjs)
library(shinyWidgets)
library(lubridate)

ui <- fluidPage(
  
  useShinyjs(),
  sidebarPanel(
    selectInput("fecha", "Fecha", choices = c("Manual", "Tiempo Real")),
    
    conditionalPanel("input.fecha == 'Manual'",
                     airDatepickerInput("ini_manual", label = "Fecha Inicio", value = Sys.time() - 3 * (60 * 60), 
                                        addon = 'none',  timepicker = TRUE,  firstDay = 1,
                                        width = "200px", autoClose = TRUE,  timepickerOpts = timepickerOptions(timeFormat = "hh:ii")),
                     airDatepickerInput("fin_manual", label = "Fecha Fin", value = Sys.time(), 
                                        addon = 'none', timepicker = TRUE, firstDay = 1, 
                                        width = "200px", autoClose = TRUE, maxDate = NULL,  timepickerOpts = timepickerOptions(timeFormat = "hh:ii"))
    ),
    
    conditionalPanel("input.fecha == 'Tiempo Real'",
                     materialSwitch(inputId = "refresh", label = "Tiempo Real", value = TRUE, status = "success")
                     
    ),
    actionButton("btnConsulta", "Lanzar Consulta"),
    actionButton("btnCancelarConsulta", "Cancelar Consulta")
  ),
  
  mainPanel(
    tableOutput("tablaResultado")
    
  )
)


server <- function(input, output, session) {
  
  # Reactive variable to store the last update time in real time
  last_refresh_time <- reactiveVal(NULL)
  
  # Reactive event for query button and real time
  consulta_evento <- eventReactive(input$btnConsulta,
                                   {
                                     if (input$fecha == "Manual") {
                                       # Get fecha_ini and fecha_fin
                                       fecha_ini <- input$ini_manual
                                       fecha_fin <- input$fin_manual
                                       
                                       # Make data frame 
                                       resultado <- data.frame(
                                         fecha = as.character(seq.POSIXt(from = fecha_ini, to = fecha_fin, by = "hour")),
                                         Valor = rnorm(length(seq.POSIXt(from = fecha_ini, to = fecha_fin, by = "hour")))
                                       )
                                       
                                       resultado
                                       
                                     } else {
                                       
                                       last_refresh_time(Sys.time())
                                       # Realizar la lógica de la consulta para tiempo real aquí
                                       consulta_tiempo_real <- data.frame(
                                         fecha = as.character(seq.POSIXt(from = Sys.time(), by = "hour", length.out = 5)),
                                         Valor = rnorm(5)
                                       )
                                       
                                       consulta_tiempo_real
                                       
                                       
                                     }
                                   }
  )
  
  
  
  # Update real time with JS
  observe({
    if (input$fecha == "Tiempo Real" && input$refresh == TRUE) {
      shinyjs::runjs(
        'consultaInterval = setInterval(function() { Shiny.setInputValue("btnConsulta", Math.random(), {priority: "event"}); }, 5000);'
      )
    }
    
    else if (input$fecha == "Tiempo Real" && input$refresh == FALSE){
      shinyjs::runjs('clearInterval(consultaInterval);')
      output$tablaResultado <- renderTable({
        data.frame(NULL)
      })
    }
    else{
      consulta_evento()
    }
    
    
  })
  
  
  output$tablaResultado <- renderTable({
    req(input$btnConsulta)
    
    consulta_evento()
  })
  
  
  
}

shinyApp(ui, server) 

我希望获得有关如何处理此问题的指导。

javascript shiny reactive-programming real-time cancel-button
1个回答
0
投票

我不完全理解您的问题和您的应用程序,因此我的答案很可能不完整和/或不是您期望的答案。在这种情况下,请发表评论告诉我我做错了什么,我会更新我的答案。

首先,有几点评论。这是行不通的:

      shinyjs::runjs(
        'consultaInterval = setInterval(function() { Shiny.setInputValue("btnConsulta", Math.random(), {priority: "event"}); }, 5000);'
      )
    }
......
      shinyjs::runjs('clearInterval(consultaInterval);')

因为两个不同

shinyjs::runjs
中的JavaScript命令无法相互通信。

此外,

btnConsulta
是Shiny操作按钮的id,其值在每次点击时都会递增,所以如果你混合操作按钮值和
input$btnConsulta
,我不知道
Shiny.setInputValue("btnConsulta"
的行为。

在观察结束时,您有:

    else{
      consulta_evento()
    }

但是

consulta_evento()
返回
consulta_evento
的值,所以这段代码什么也不做。我猜你想做的是
consulta_evento(data.frame(NULL))

现在,这是我的解决方案。将下面的 JavaScript 代码保存在应用程序中 www 子文件夹中的文件 refresh.js 中:

$(document).ready(function() {
  let intervalId;
  let $switch = $("#refresh");
  let $select = $("#fecha");
  let $cancel = $("#btnCancelarConsulta");
  function refresh() {
    intervalId = setInterval(function() {
      Shiny.setInputValue("observe", true, {priority: "event"});
    }, 5000);
  }
  function stopRefresh() {
    if(intervalId) {
      clearInterval(intervalId);
      intervalId = null;
      Shiny.setInputValue("clear", true, {priority: "event"});
      $switch.prop("checked", false);
    }
  }
  if($select.val === "Tiempo Real") {
    if($switch.prop("checked")) {
      refresh();
    } else {
      stopRefresh();
    }
  } else {
    stopRefresh();
  }
  $cancel.on("click", function() {
    stopRefresh();
  });
  $switch.on("change", function() {
    if($select.val() === "Tiempo Real") {
      if($switch.prop("checked")) {
        refresh();
      } else {
        stopRefresh();
      }
    }
  });
  $select.on("change", function() {
    if($select.val() === "Manual") {
      stopRefresh();
    }
  });
});

这是闪亮的应用程序:

library(shiny)
library(shinyWidgets)
library(lubridate)

ui <- fluidPage(
  tags$head(tags$script(src = "refresh.js")),
  
  sidebarPanel(
    selectInput("fecha", "Fecha", choices = c("Manual", "Tiempo Real")),
    
    conditionalPanel(
      "input.fecha == 'Manual'",
      airDatepickerInput("ini_manual", label = "Fecha Inicio", value = Sys.time() - 3 * (60 * 60), 
                         addon = 'none',  timepicker = TRUE,  firstDay = 1,
                         width = "200px", autoClose = TRUE,  timepickerOpts = timepickerOptions(timeFormat = "hh:ii")),
      airDatepickerInput("fin_manual", label = "Fecha Fin", value = Sys.time(), 
                         addon = 'none', timepicker = TRUE, firstDay = 1, 
                         width = "200px", autoClose = TRUE, maxDate = NULL,  timepickerOpts = timepickerOptions(timeFormat = "hh:ii"))
    ),
    
    conditionalPanel(
      "input.fecha == 'Tiempo Real'",
      materialSwitch(
        inputId = "refresh", label = "Tiempo Real", value = TRUE, status = "success"
      )
    ),
    
    actionButton("btnConsulta", "Lanzar Consulta"),
    actionButton("btnCancelarConsulta", "Cancelar Consulta")
  ),
  
  mainPanel(
    tableOutput("tablaResultado")
  )
)


server <- function(input, output, session) {
  
  # Reactive variable to store the last update time in real time
  last_refresh_time <- reactiveVal(NULL)
  
  consulta_evento <- reactiveVal(data.frame(NULL))
  
  # Reactive event for query button and real time
  observeEvent(
    list(input$btnConsulta, input$observe),
    {
      if(input$fecha == "Manual") {
        # Get fecha_ini and fecha_fin
        fecha_ini <- input$ini_manual
        fecha_fin <- input$fin_manual
        # Make data frame 
        resultado <- data.frame(
          fecha = as.character(seq.POSIXt(from = fecha_ini, to = fecha_fin, by = "hour")),
          Valor = rnorm(length(seq.POSIXt(from = fecha_ini, to = fecha_fin, by = "hour")))
        )
        
        consulta_evento(resultado)
        
      } else {
        
        last_refresh_time(Sys.time())
        # Realizar la lógica de la consulta para tiempo real aquí
        consulta_tiempo_real <- data.frame(
          fecha = as.character(seq.POSIXt(from = Sys.time(), by = "hour", length.out = 5)),
          Valor = rnorm(5)
        )
        
        consulta_evento(consulta_tiempo_real)
        
      }
    }
  )
  
  observeEvent(input$clear, {
    consulta_evento(data.frame(NULL))
  })

  
  output$tablaResultado <- renderTable({
    consulta_evento()
  })
  
}

shinyApp(ui, server) 
© www.soinside.com 2019 - 2024. All rights reserved.