简体   繁体   English

在闪亮的流中创建动态数量的卡片元素

[英]Create dynamic number of card elements in shiny flowLayout

I like to fill an area in a shiny app with card elements. 我喜欢用卡片元素填充闪亮的应用程序中的区域。 The items flow into the next row when there is not enough space. 如果没有足够的空间,这些项目将流入下一行。 This can be achieved with flowLayout . 这可以通过flowLayout实现。

在此处输入图片说明

But I do not know the number of items in advance, so I need to create the card elements in a loop. 但是我不知道物品的数量,所以我需要循环创建卡片元素。 But when I use lapply inside flowLayout all elements are shown below each other. 但是,当我在flowLayout使用lapply时,所有元素都显示在彼此下面。

How to fix this, so that items are shown in rows next to each other? 如何解决此问题,使项目以相邻的行显示?

library(shiny)

card <- function(.img, .species, .sepal.length) {
  HTML(
    paste0(
      '<div class="card">
      <img src="', .img, '" style="width:100%">
      <div class="container">
      <h4><i>', .species, '</i></h4>
      <hr>
      <p>Sepal Length: ', .sepal.length, '</p>
      </div>
      </div>')
  )
}

img.src <- "https://www.plant-world-seeds.com/images/item_images/000/007/023/large_square/iris_baby_blue.jpg?1500653527"

ui <- fluidPage(
  tags$head(tags$style('.card {
                         width: 250px;
                       clear: both;
                       /* Add shadows to create the "card" effect */
                       box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
                       transition: 0.3s;
                       }
                       /* On mouse-over, add a deeper shadow */
                       .card:hover {
                       box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
                       }
                       /* Add some padding inside the card container */
                       .container {
                       width: 250px;
                       padding: 2px 16px;
                       }')),
  uiOutput("cards")
)

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

  # This looks as expected

  # output$cards <- renderUI({
  #   shiny::flowLayout(
  #     cellArgs = list(
  #       style = "
  #           width: auto;
  #           height: auto;
  #           margin: 5px;
  #           "),
  #     card(img.src,
  #          .species = iris[1, "Species"],
  #          .sepal.length = iris[1, "Sepal.Length"]),
  #     card(img.src,
  #          .species = iris[2, "Species"],
  #          .sepal.length = iris[2, "Sepal.Length"]),
  #     card(img.src,
  #          .species = iris[3, "Species"],
  #          .sepal.length = iris[3, "Sepal.Length"]),
  #     card(img.src,
  #          .species = iris[4, "Species"],
  #          .sepal.length = iris[4, "Sepal.Length"])
  #   )
  # })

  # Now elements are below each other when using lapply

  output$cards <- renderUI({
    shiny::flowLayout(
      cellArgs = list(
        style = "
        width: auto;
        height: auto;
        margin: 5px;
        "),
      lapply(1:4, function(.x) card(img.src,
                       .species = iris[.x, "Species"],
                       .sepal.length = iris[.x, "Sepal.Length"]))
      )
  })
}

shinyApp(ui, server)

The comment above links to an answer that works, but there is a much easier way. 上面的评论链接到了一个可行的答案,但是有一种更简单的方法。

Instead of using lapply (which makes a list, confusing flowLayout ), we can use do.call to expand the argument. 可以使用do.call来扩展参数,而不是使用lapply (它使列表混乱,使flowLayout混乱)。

Updated server function: 更新的服务器功能:

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

  output$cards <- renderUI({

    # First make the cards
    args <- lapply(1:4, function(.x) card(img.src,
                                  .species = iris[.x, "Species"],
                                  .sepal.length = iris[.x, "Sepal.Length"]))

    # Make sure to add other arguments to the list:
    args$cellArgs <- list(
      style = "
        width: auto;
        height: auto;
        margin: 5px;
        ")

    # basically the same as flowLayout(cards[[1]], cards[[2]],...)
    do.call(shiny::flowLayout, args)

  })
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM