【问题标题】:make shiny app UI dependent on URL parameter使闪亮的应用程序 UI 依赖于 URL 参数
【发布时间】:2018-07-10 18:27:49
【问题描述】:

我想根据 URL 参数为我的应用创建替代 UI。具体来说,我想使用来自 shinyWidgets 的下拉选择器输入而不是 checkboxGroupInput,但前提是参数 mini=TRUE 通过 URL 传递

library(shinyWidgets)

nazwy=c('Warszawa', 'Krakow', 'Gdansk')

ui<-fluidPage(
 if (mini) {
    pickerInput(inputId = "miasto", choices = nazwy,multiple = TRUE)
 } else {
  checkboxGroupInput('miasto', nazwy)
 })

我可以使用条件面板以某种方式做到这一点,还是 renderUI 是我唯一的选择?

或者,我可以根据窗口宽度使pickerInput 或 checkboxGroupInput 出现吗?

更新

下面给出的选项 1 是对我最初问题的有效答案,使 UI 依赖于 URL。对于这种特殊情况,选项 2 是更好的解决方案 - 使 UI 适应窗口大小。但是,要使选项 2 正常工作,需要另一个变量来存储选择,以便每次调整窗口大小时 select/pickerInput 不会返回默认选择。我相应地编辑了代码。

【问题讨论】:

    标签: r shiny shiny-server


    【解决方案1】:

    以下四个选项:

    1. 依赖于 URL,renderUI
    2. 取决于窗口宽度,renderUI
    3. 取决于窗口宽度,conditionalPanel(不能正常工作)
    4. 取决于窗口宽度,shinyjs

    选项 1:依赖于 URL,renderUI

    可以使其依赖于 URL,例如 here。这是一个示例实现:

    library(shinyWidgets)
    library(shiny)
    
    nazwy=c('Warszawa', 'Krakow', 'Gdansk')
    
    ui<-fluidPage(
      uiOutput('myUI')
    )
    
    
    server <- function(input,output,session) {
    
      output$myUI <- renderUI({
        query <- parseQueryString(session$clientData$url_search)
        if (!is.null(query$mini)) {
          if(query$mini==TRUE)
          {
            pickerInput(inputId = "miasto", choices = nazwy,multiple = TRUE)
          }
          else
          {
            checkboxGroupInput('miasto', 'choose: ',nazwy)
          }
        } 
        else 
        {
          checkboxGroupInput('miasto', 'choose: ',nazwy)
        }
      }) 
    }
    
    shinyApp(ui,server,options=list(port=7777))
    

    尝试http://127.0.0.1:7777/http://127.0.0.1:7777/?mini=TRUE


    选项2:取决于窗口宽度,renderUI

    如果你想让它依赖于窗口宽度,这里有一个可能的解决方案:

    library(shinyWidgets)
    library(shiny)
    
    nazwy=c('Warszawa', 'Krakow', 'Gdansk')
    
    ui<-fluidPage(
      tags$head(tags$script('
                                    var dimension = [0, 0];
                            $(document).on("shiny:connected", function(e) {
                            dimension[0] = window.innerWidth;
                            dimension[1] = window.innerHeight;
                            Shiny.onInputChange("dimension", dimension);
                            });
                            $(window).resize(function(e) {
                            dimension[0] = window.innerWidth;
                            dimension[1] = window.innerHeight;
                            Shiny.onInputChange("dimension", dimension);
                            });
                            ')),
      uiOutput('myUI')
    )
    
    
    server <- function(input,output) {
       output$myUI <- renderUI({
         req(input$dimension)
         if (input$dimension[1]<800) {
            pickerInput(inputId = "miasto", choices = nazwy, 
                         selected=isolate(selected_cities()),multiple = TRUE)
         } else {
            checkboxGroupInput('miasto', 'choose: ',
                         choices=nazwy, selected=isolate(selected_cities()))
         }
       })
    
       #store selected value to pass on resizing
       selected_cities<-reactive(input$miasto) 
    
    }
    
    shinyApp(ui,server)
    

    选项 3:窗口宽度 + 条件面板。 注意:无法按预期工作。

       library(shinyWidgets)
        library(shiny)
    
        nazwy=c('Warszawa', 'Krakow', 'Gdansk')
    
        ui<-fluidPage(
          tags$head(tags$script('var dimension = [0, 0];
                                $(document).on("shiny:connected", function(e) {
                                dimension[0] = window.innerWidth;
                                dimension[1] = window.innerHeight;
                                Shiny.onInputChange("dimension", dimension);
                                });
                                $(window).resize(function(e) {
                                dimension[0] = window.innerWidth;
                                dimension[1] = window.innerHeight;
                                Shiny.onInputChange("dimension", dimension);
                                });
                                ')),
          conditionalPanel(condition = 'input.dimension[0]>1000',
                           pickerInput(inputId = "miasto", choices = nazwy,multiple = TRUE)
          ),
          conditionalPanel(condition = 'input.dimension[0]<=1000',
                           checkboxGroupInput('miasto', 'choose: ',nazwy))
        )
    
    
        server <- function(input,output) {
    
        }
    
        shinyApp(ui,server)
    

    选项4:窗口宽度+shinyjs

    library(shinyWidgets)
    library(shiny)
    library(shinyjs)
    
    nazwy=c('Warszawa', 'Krakow', 'Gdansk')
    
    ui<-fluidPage(
      tags$head(tags$script('var dimension = [0, 0];
                            $(document).on("shiny:connected", function(e) {
                            dimension[0] = window.innerWidth;
                            dimension[1] = window.innerHeight;
                            Shiny.onInputChange("dimension", dimension);
                            });
                            $(window).resize(function(e) {
                            dimension[0] = window.innerWidth;
                            dimension[1] = window.innerHeight;
                            Shiny.onInputChange("dimension", dimension);
                            });
                            ')),
      div(id='div1',pickerInput(inputId = "miasto", choices = nazwy,multiple = TRUE)),
      shinyjs::hidden(div(id='div2',checkboxGroupInput('miasto', 'choose: ',nazwy))),
      useShinyjs()
    )
    
    
    server <- function(input,output) {
      observeEvent(input$dimension,ignoreNULL=T,{
        if (input$dimension[1]>1000) {
          shinyjs::show('div1')
          shinyjs::hide('div2')    
        } else {
          shinyjs::show('div2')
          shinyjs::hide('div1')   
        }
      }) 
    }
    
    shinyApp(ui,server)
    

    【讨论】:

    • 谢谢!我尝试了您的窗口宽度解决方案,除了它产生的警告(如果:参数长度为零时出错)之外,它还可以工作。可以通过添加 'req(input$dimension)' 来修复;但是,这两种解决方案都使用了 renderUI,我希望避免这种情况
    • @MonikaP,我添加了一个使用条件面板 + 窗口宽度的示例。但是,我不知道对 URL 参数执行相同操作的干净方法,我真的认为在这种情况下,renderUI 将是可行的方法。希望这会有所帮助!
    • 我上传了Dimension+renderUI方案(方案2)到服务器。事情是这样的:在一个固定宽度的 iframe 中它工作得很好。在智能手机上,当我滚动时,pickerInput 会不断恢复为“selected=”定义的原始值。尽管我没有调整智能手机上的窗口大小,但不知何故触发了 javascript...?
    • 这很奇怪!您可以将console.log(window.innerWidth); 添加到javascript,并在滚动时检查控制台记录的内容吗?如果它实际上没有改变,也许我们可以在两者之间添加一个 reactiveVal 并使 renderUI 依赖于它。
    • 哈!发现错误。您的代码指的是窗口高度而不是宽度
    猜你喜欢
    • 2016-04-10
    • 2017-08-20
    • 1970-01-01
    • 2015-12-28
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 2016-05-23
    相关资源
    最近更新 更多