ユーザが(actionButtonを介して)いくつかの条件を追加し、それらの条件の値を選択できる動的フォームを構築しようとしています。彼が選択を終えると、彼は計算を開始するかもしれません。 すべての条件は「削除」ボタンで削除できます。Shiny:動的フォーム/ ui:リスト内の最後のオブザーバがトリガしないremoveUI
これは、関連する削除ボタンに反応しない最後に挿入されたコンポーネントを除いて、すべて正常に機能します。 最後のコンポーネントは、[条件の追加]ボタンがクリックされた場合にのみ削除されます。
これはバグですか、私の間違いを指摘できますか?
私はコンポーネントを構築するためにrenderUIでobserveEventを使用しています:server.R
で
observeEvent(input$go, {
output$ui <- renderUI({
rows <- lapply(names(components),buildComponent)
res = do.call(fluidRow, rows)
})
makeObservers()
})
makeObserversは、すべてのコンポーネントのためのobserveEvent閉鎖作成します。
makeObservers <- eventReactive(input$go, {
IDs <- names(components)
new_ind <- !(IDs %in% vals$y)
res <- lapply(IDs[new_ind], function (x) {
observeEvent(input[[paste0("rmv", x)]], {
if(components[[x]] == "Main1") removeComponent(x)
})
})
} ,
ignoreNULL = F, ignoreInit = F)
を見つけてください。実例
library(shiny)
library(shinythemes)
criterias <- c("Criteria 1", "Criteria 2", "Criteria 3", "Criteria 4")
components <<- list()
counter <<- 0
buildComponent <- function(val) {
idselect = paste0("select", val)
idremove <- paste0("rmv", val)
div(
selectInput(idselect, "criteria :", criterias, criterias[0]),
actionButton(idremove, paste0("X", val),icon = icon("remove"), size = "small")
)
}
removeComponent <- function(x) {
print(paste0("Removing" ,x))
xpath1 = paste0("div:has(> #select", x ,")")
xpath2 = paste0("div:has(> #rmv", x ,")")
removeUI(
selector = xpath1, multiple = T#, immediate=T
)
removeUI(
selector = xpath2, multiple = T#, immediate=T
)
components[[as.character(x)]] <<- NULL
}
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("go", "Criteria", icon = icon("plus-circle"),
size = "small"),
uiOutput("ui")
),
mainPanel(
actionButton("activate", "show cpts"),
textOutput('show_components')
)
))
server <- shinyServer(function(input, output, session) {
# Keep track of which observer has been already created
vals <- reactiveValues(y = NULL)
makeObservers <- eventReactive(input$go, {
IDs <- names(components)
new_ind <- !(IDs %in% vals$y)
print("new_ind")
print(IDs[new_ind])
# update reactive values
vals$y <- names(components)
res <- lapply(IDs[new_ind], function (x) {
observeEvent(input[[paste0("rmv", x)]], {
print(paste0("rmv", x))
print(components[[x]])
if(components[[x]] == "Main1") removeComponent(x)
})
})
} , ignoreNULL = F, ignoreInit = F)
observeEvent(input$go, {
output$ui <- renderUI({
print(counter)
counter <<- counter + 1
components[[as.character(counter)]] <<- "Main1"
print("adding component : ")
print(paste0(names(components),collapse = ";"))
rows <- lapply(names(components),buildComponent)
res = do.call(fluidRow, rows)
})
makeObservers()
})
observeEvent(input$activate, {
output$show_components <- renderPrint({
components
})
})
})
shinyApp(ui, server)
Mike Wiseの偉大な発言のおかげで、私は正確な問題を見つけることができました:(Mikeの答えを見てください)。ここではいくつかのコードは次のとおりです。
library(shiny)
library(shinythemes)
criterias <- c("Criteria 1", "Criteria 2", "Criteria 3", "Criteria 4")
components <<- list()
counter <<- 0
buildComponent <- function(val) {
idselect = paste0("select", val)
idremove <- paste0("rmv", val)
div(
selectInput(idselect, "criteria :", criterias, criterias[0]),
actionButton(idremove, paste0("X", val),icon = icon("remove"), size = "small")
)
}
removeComponent <- function(x) {
print(paste0("Removing" ,x))
xpath1 = paste0("div:has(> #select", x ,")")
xpath2 = paste0("div:has(> #rmv", x ,")")
removeUI(
selector = xpath1, multiple = T#, immediate=T
)
removeUI(
selector = xpath2, multiple = T#, immediate=T
)
components[[as.character(x)]] <<- NULL
}
ui <- shinyUI(fluidPage(
sidebarPanel(
actionButton("go", "Criteria", icon = icon("plus-circle"),
size = "small"),
uiOutput("ui")
),
mainPanel(
actionButton("activate", "show cpts"),
textOutput('show_components')
)
))
server <- shinyServer(function(input, output, session) {
# Keep track of which observer has been already created
vals <- reactiveValues(y = NULL)
makeObservers <- eventReactive(input$go, {
IDs <- names(components)
new_ind <- !(IDs %in% vals$y)
print("new_ind")
print(IDs[new_ind])
# update reactive values
vals$y <- names(components)
res <- lapply(IDs[new_ind], function (x) {
observeEvent(input[[paste0("rmv", x)]], {
print(paste0("rmv", x))
print(components[[x]])
if(components[[x]] == "Main1") removeComponent(x)
})
})
} , ignoreNULL = F, ignoreInit = F)
observeEvent(input$go, {
counter <<- counter + 1
components[[as.character(counter)]] <<- "Main1"
output$ui <- renderUI({
print(counter)
print("adding component : ")
print(paste0(names(components),collapse = ";"))
rows <- lapply(names(components),buildComponent)
res = do.call(fluidRow, rows)
})
makeObservers()
})
observeEvent(input$activate, {
output$show_components <- renderPrint({
components
})
})
})
shinyApp(ui, server)
はあなたの助けと改善のためにありがとうございました。 – tokiloutok
renderUIのグローバル変数を更新すると、正確な問題が発生します。counter << - counter + 1およびcomponents [[as.character(counter)]] << - "Main1"。彼らが上位レベル(observeEvent)に戻るときに、少なくともエレガントでないコードが動作します。私の質問の末尾にある作業コードを参照してください。 – tokiloutok
まだ<<を使用することはお勧めできません。通常、反応値を使用することで回避できます。そして私が助けてくれることをうれしく思います。 –