在使用服务器端循环创建 Shiny UI 元素(Shiny Dashboard 框)时,不需要额外的东西
Something unwanted extra, when creating Shiny UI elements (Shiny Dashboard boxes) in using a server side loop
我正在测试通过服务器端的循环动态创建 Shiny UI 元素的方法,用户可以控制实际生成的元素数量。在我的例子中,元素是带有两个下拉菜单和一个按钮的 Shiny Dashboard 框。一切正常,除了打印出一些额外的东西,正如您从图像中看到的那样:
我的 ui.r 看起来如下:
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
...和 server.r 看起来如下:
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = c()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- c(boxlist,column(1, box(ddmenu1, ddmenu2, button)))
}
boxlist
})
})
那么这个“div col-sm-1”乘以箱子数量的垃圾是从哪里来的,我该如何摆脱它?
我建议使用 lapply
而不是使用 for 循环。
is explained why this is advantageous. Also see this overview.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
server <- function(input, output, session) {
output$boxes <- renderUI({
lapply(seq_len(input$numberOfBoxes), function(i){
box(
selectInput(paste0("ddmenu1_in_box", i), "Animal", list('cat', 'dog', 'rabbit')),
selectInput(paste0("ddmenu2_in_box", i), "Color", list('red', 'blue', 'green')),
actionButton(paste0("justabutton_in_box", i), "Click me!")
)
})
})
}
shinyApp(ui, server)
既然“废话”存在于列表对象的某处,我决定仔细研究一下。
所以我开发了这个“hack”来用空字符串覆盖文本:
ui.r(无修改)
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
server.r(这次包括一个覆盖不需要的字符串的循环)
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = list()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- append(boxlist,(column(1, box(ddmenu1, ddmenu2, button))))
}
#Let's go through every attribute
for(i in 1:length(attributes(boxlist)$names)) {
#If the attribute name is NOT "children"
if(attributes(boxlist)$names[i] != "children") {
#...and the length of corresponding variable "name" equals one (text string)...
if(length(boxlist[i]$name) == 1) {
boxlist[i]$name <- ''
}
#...and the length of corresponding variable "attribs$class" equals one (text string)...
if(length(boxlist[i]$attribs$class) == 1) {
boxlist[i]$attribs$class <- ''
}
}
}
boxlist
})
})
老实说,我认为这样做是错误的,必须有更好的方法来进行,但是直到有人 post 在这里,这似乎是要走的路。至少废话不见了:
我正在测试通过服务器端的循环动态创建 Shiny UI 元素的方法,用户可以控制实际生成的元素数量。在我的例子中,元素是带有两个下拉菜单和一个按钮的 Shiny Dashboard 框。一切正常,除了打印出一些额外的东西,正如您从图像中看到的那样:
我的 ui.r 看起来如下:
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
...和 server.r 看起来如下:
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = c()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- c(boxlist,column(1, box(ddmenu1, ddmenu2, button)))
}
boxlist
})
})
那么这个“div col-sm-1”乘以箱子数量的垃圾是从哪里来的,我该如何摆脱它?
我建议使用 lapply
而不是使用 for 循环。
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
server <- function(input, output, session) {
output$boxes <- renderUI({
lapply(seq_len(input$numberOfBoxes), function(i){
box(
selectInput(paste0("ddmenu1_in_box", i), "Animal", list('cat', 'dog', 'rabbit')),
selectInput(paste0("ddmenu2_in_box", i), "Color", list('red', 'blue', 'green')),
actionButton(paste0("justabutton_in_box", i), "Click me!")
)
})
})
}
shinyApp(ui, server)
既然“废话”存在于列表对象的某处,我决定仔细研究一下。
所以我开发了这个“hack”来用空字符串覆盖文本:
ui.r(无修改)
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
server.r(这次包括一个覆盖不需要的字符串的循环)
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = list()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- append(boxlist,(column(1, box(ddmenu1, ddmenu2, button))))
}
#Let's go through every attribute
for(i in 1:length(attributes(boxlist)$names)) {
#If the attribute name is NOT "children"
if(attributes(boxlist)$names[i] != "children") {
#...and the length of corresponding variable "name" equals one (text string)...
if(length(boxlist[i]$name) == 1) {
boxlist[i]$name <- ''
}
#...and the length of corresponding variable "attribs$class" equals one (text string)...
if(length(boxlist[i]$attribs$class) == 1) {
boxlist[i]$attribs$class <- ''
}
}
}
boxlist
})
})
老实说,我认为这样做是错误的,必须有更好的方法来进行,但是直到有人 post 在这里,这似乎是要走的路。至少废话不见了: