【问题标题】:Shiny Responds to Enter闪亮响应进入
【发布时间】:2015-10-03 14:27:23
【问题描述】:

我有一个 textInput 小部件,现在每当我开始在小部件中输入内容时,shinyApp 都会尝试评估 textInput 小部件中未完成的内容并导致许多错误。我知道添加一个动作按钮“计算”可以轻松解决问题。但是,我的应用程序没有空间再放一个按钮。所以,我想知道 textInput 小部件是否有办法“监听”键盘事件,例如当用户点击“Enter”时?提前致谢!

【问题讨论】:

标签: r shiny


【解决方案1】:

非常好的问题。这是我使用方式的一个例子;这个应用程序显示了一个 ggplot,用户在一个文本框中给出了 ggplot 的标题 - 但标题更改仅在按下“返回”时才会做出反应:

js <- '
$(document).on("keyup", function(e) {
  if(e.keyCode == 13){
    Shiny.onInputChange("keyPressed", Math.random());
  }
});
'

shinyApp(
  ui = bootstrapPage(

    tags$script(js),

    textInput("title", label = "Title"),

    plotOutput("ggplot")
  ),

  server = function(input, output, session){

    Title <- reactiveVal()

    observeEvent(input[["keyPressed"]], {
      Title(input[["title"]])
    })

    output[["ggplot"]] <- renderPlot({
      ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) +
        geom_point() +
        ggtitle(Title())
    })

  }
)

说明:

这段 Javascript 代码:

$(document).on("keyup", function(e) {
  if(e.keyCode == 13){
    Shiny.onInputChange("keyPressed", Math.random());
  }
});

创建一个新的 Shiny 输入,即input$keyPressed,当在任意位置按下“Return”键时,它会接收一个随机数。

然后我定义了一个响应值,它采用用户在文本框中给出的值 input$title,仅当 input$keyPressed 更改时:

Title <- reactiveVal()

observeEvent(input[["keyPressed"]], {
  Title(input[["title"]])
})

最后我将这个反应值传递给ggtitle

output[["ggplot"]] <- renderPlot({
  ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) +
    geom_point() +
    ggtitle(Title())
})

【讨论】:

    【解决方案2】:

    这是我构建的一个应用,解决了类似的问题。

    我们的想法是同时聆听按键和按钮,并确保它们能够很好地协同工作。在您的情况下,您应该能够使事情变得更简单,因为您不需要按钮。

    希望你喜欢。

    library(shiny)
    # This is a demo app to test a key binding on an actionButton
    # Uncommenting the info item (on both UI and server) will display internal stuff
    runApp( 
      list(
        #############################################
        # UI 
        #############################################
        ui = bootstrapPage(
          textInput ("myinput", label = "Write something here"),
          tags$script('
            $(document).on("keydown", function (e) {
            Shiny.onInputChange("lastkeypresscode", e.keyCode);
            });
            '),
          actionButton("GO", "Lancer le matching !"),
          # verbatimTextOutput("info"),
          verbatimTextOutput("results")
        ), 
    
        #############################################
        # SERVER 
        #############################################
        server = function(input, output, session) {
    
          # There are state variables for the input text and GO button
          curr.val <- "" # Corresponds to the current displayed input$myinput
          curr.go  <- 0  # Corresponds to the last known GO value (integer)
    
          lastEvent <- reactive({
            # Is reactive to the following events
            input$GO
            input$lastkeypresscode
    
            # Decide which action should be taken
            if(input$GO > curr.go) {
              # The user pushed the GO actionButton, so take action
              action <- 1
              curr.go <<- input$GO
            } else if(input$lastkeypresscode == 13) {
              # The user pressed the Enter key, so take action
              action <- 1
            } else {
              # The user did anything else, so do nothing
              action <- 0
            }
    
            return(action)
          })
    
          output$results = renderPrint({
            if(lastEvent() == 1) {
              curr.val <<- isolate(input$myinput)
            }
            curr.val
          })
    
          # output$info = renderText({
          #   paste(curr.val, curr.go, input$lastkeypresscode, sep = ", ")
          # })
        }
      )
    )
    

    【讨论】:

      【解决方案3】:

      我创建了一个简单的应用程序作为示例,用户可以在其中输入城市名称,然后按 ENTER 后返回纬度和经度:

      library(shiny)
      library(ggmap)
      
      
      runApp( 
        list(
          #############################################
          # UI 
          #############################################
      ui = fluidPage( title = "City Search" ,
                      position= "static-top",
                      tags$script(' $(document).on("keydown", function (e) {
                                                        Shiny.onInputChange("lastkeypresscode", e.keyCode);
                                                        });
                                                        '),
                      # Search panel:
                      textInput("search_city", "" , placeholder= "City"),
                      verbatimTextOutput("results")), 
      
          #############################################
          # SERVER 
          #############################################
      server = function(input, output, session) {
      
        observe({
          if(!is.null(input$lastkeypresscode)) {
            if(input$lastkeypresscode == 13){
              target_pos = geocode(input$search_city, messaging =FALSE)
              LAT = target_pos$lat
              LONG = target_pos$lon
              if (is.null(input$search_city) || input$search_city == "")
                return()
              output$results = renderPrint({
                sprintf("Longitude: %s ---- Latitude: %s", LONG, LAT)
              })
            }
          }
        })
      }
      )
      )
      

      请注意,要捕获 ENTER 输入,代码是 13,即input$lastkeypresscode == 13

      【讨论】:

        【解决方案4】:

        在您的情况下,问题在于反应式编程,这就是您需要一些东西来管理这种情况的原因。我的建议是使用observer patternvalidate function

        • 观察者模式:shiny 实现了观察者模式,它是 在对象中发生事件时采取行动(可以是点击 在按钮中,输入中的新值...)。

        • 验证函数:此过程的功能类似于 if/else 语句。确实,需要检查 参数,如果值错误,会有错误提示。

        要了解如何使用观察模式和验证功能,请单击上一个链接(在 Shiny 网站中已说明所有内容)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-10
          • 1970-01-01
          • 1970-01-01
          • 2020-08-18
          • 2020-05-22
          • 1970-01-01
          • 2013-07-16
          相关资源
          最近更新 更多