2016-08-23 87 views
5

我想模塊化一個複雜的Shiny應用程序,我有一個conditionalPanel應該只顯示給定的輸入狀態。R帶條件面板和反應的閃亮模塊

之前我做了一切模塊化,輸入和conditionalPanel均在ui.R,我可以用這樣的參考輸入:

conditionalPanel("input.select == 'Option one'", p('Option one is selected')) 

現在,我已經模塊化的東西,訪問輸入更復雜。我認爲以下是做到這一點的方法,但它不起作用。 (在這裏,我的東西結合成一個單一的獨立腳本):

library(shiny) 

## Module code for 'selectorUI' and 'selector' 
selectorUI <- function(id) { 
    ns <- NS(id) 
    selectizeInput(inputId = ns('select'), 
       label = 'Make a choice:', 
       choices = c('Option one', 'Option two')) 
} 

selector <- function(input, output, session) { 
    reactive(input$select) 
} 

## Main app 
ui <- shinyUI(fluidPage(
    selectorUI('id1'), 
    conditionalPanel(condition = "output.selected == 'Option one'", p('Option one is selected.')) 
)) 

server <- shinyServer(function(input, output, session) { 
    output$selected <- callModule(selector, 'id1') 
}) 

shinyApp(ui = ui, server = server) 

我認爲這應該工作,但它沒有 - 如果我再拍參考output$selected在主界面部分它只:

ui <- shinyUI(fluidPage(
    selectorUI('id1'), 
    textOutput('selected'), ## Adding just this one line makes the next line work 
    conditionalPanel(condition = "output.selected == 'Option one'", p('Option one is selected.')) 
)) 

不幸的是,當然這會產生textOutput('selected')的結果的不良影響。我只能猜測這個原因起作用是因爲它以某種方式觸發了反應,而JavaScript引用本身沒有。

任何想法我應該如何讓這個條件面板正常工作?

謝謝。

編輯:原來並不是一個真正的錯誤:https://github.com/rstudio/shiny/issues/1318。在下面看到我自己的答案。

但也請注意,我實際上喜歡接受答案中給出的renderUI解決方案比我的原始conditionalPanel方法更好。

回答

4

調用模塊後,selectizeInput的ID爲id1-select。在JavaScript中有訪問對象屬性的兩種方式:

objectName.propertyobjectName['property']

由於在ID我們必須通過字符串引用它-,所以第二個方法是路要走。

conditionalPanel條件變爲:

input['id1-select'] == 'Option one' 

完整例如:

library(shiny) 

## Module code for 'selectorUI' and 'selector' 
selectorUI <- function(id) { 
    ns <- NS(id) 
    selectizeInput(inputId = ns('select'), 
       label = 'Make a choice:', 
       choices = c('Option one', 'Option two')) 
} 

## Main app 
ui <- shinyUI(fluidPage(
    selectorUI('id1'), 
    conditionalPanel(condition = "input['id1-select'] == 'Option one'", 
        p('Option one is selected.')) 
)) 

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

}) 

shinyApp(ui = ui, server = server) 

編輯:

這是行得通的,但是這不違反模塊化的概念嗎?您必須知道模塊的代碼在內部調用輸入'select'才能構建'id1-select'。

是的,你說得對。

根據這article,你使用的技巧,即分配一個模塊調用到輸出$選擇,然後通過output.selected訪問客戶端的值應該工作,但它不會。我不知道爲什麼......這可能是一個錯誤。 (我有從GitHub最新版本閃亮)

我能想到的唯一的事情就是用renderUI,而不是conditionalPanel如下面的例子:

library(shiny) 
## Module code for 'selectorUI' and 'selector' 
selectorUI <- function(id) { 
    ns <- NS(id) 
    selectizeInput(inputId = ns('select'), 
       label = 'Make a choice:', 
       choices = c('Option one', 'Option two')) 
} 

selector <- function(input, output, session) { 
    reactive(input$select) 
} 

## Main app 
ui <- shinyUI(fluidPage(
    selectorUI('id1'), 
    uiOutput("dynamic1") 
)) 

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


    output$dynamic1 <- renderUI({ 
    condition1 <- callModule(selector, 'id1') # or just callModule(selector, 'id1')() 
    if (condition1() == 'Option one') return(p('Option one is selected.')) 
    }) 

}) 

shinyApp(ui = ui, server = server) 
+0

這確實有效,但是這不違反模塊化的概念嗎?您必須知道模塊的代碼在內部調用輸入'select'才能構建'id1-select'。 –

+0

是的,你是對的 - 我更新了我的文章。 –

+1

我認爲這確實是一個錯誤。我通過https://github.com/rstudio/shiny/issues/1318提供了一個更簡單的例子。我更喜歡'renderUI'解決方案,因爲'conditionalPanel'依賴於'display:none'風格來隱藏內容,而'renderUI'方法只是給出一個空的div。謝謝你寫了。 –

2

原來這實際上不是一個bug ,只是有點棘手。 According to Joe Cheng

右 - 如果默認情況下,我們不計算/呈現輸出值,如果它們不會被看到的話。如果我們不計算它們,你不能在條件下使用它們。

可以通過設置輸出來計算每一次,你可以在你server.R使用這個改變這種行爲,這(與相應的值替換outputId):

outputOptions(output, "outputId", suspendWhenHidden = FALSE)

所以要修復與我原來的例子問題,我們只需要一個行添加到服務器功能:

server <- shinyServer(function(input, output, session) { 
    output$selected <- callModule(selector, 'id1') 
    outputOptions(output, 'selected', suspendWhenHidden = FALSE) # Adding this line 
})