【问题标题】:Align elements inside a fluidRow对齐fluidRow中的元素
【发布时间】:2021-12-30 06:54:17
【问题描述】:

我有一个闪亮的应用程序,在流体行中有一些元素。根据登录,我需要显示/隐藏这些元素。但是,一旦我隐藏它们,fluidRow 中元素的对齐方式就会受到影响。

library(shiny)
library(shinyjs)
ui <- fluidPage(
  shinyjs::useShinyjs(),
  fluidRow( align = 'center',
    column(3, align="center", actionButton('b1', 'Button 1')),
    column(3, align="center", actionButton('b2', 'Button 2')),
    div(id = 'hide_this', column(3, align="center", actionButton('b3', 'Button 3'))),
    column(3, align="center", actionButton('b4', 'Button 4'))
  )
)

server <- function(input, output, session) {
  shinyjs::hide('hide_this')
}

shinyApp(ui = ui, server = server)

如果我隐藏第三个按钮,我希望剩余的按钮在流体行中对齐(占据整个宽度并均匀分布)。有没有办法做到这一点?我也尝试了fillRowfillCol,但没有任何乐趣。

【问题讨论】:

  • 我已经更新了我之前的答案

标签: r shiny


【解决方案1】:

我不确定您是如何处理登录的,所以我从 shinyauthr 包中制作了自己的基本示例。我创建了 3 个用户,user1 可以看到所有按钮,user2 只有 3 个,user3 只有 2 个。我们使用 insertUI() 在服务器中创建按钮。所以我们检查哪个用户已经登录,然后制作按钮行。如果是 user1,则显示所有按钮。如果是user2,那么一个按钮的id是“#hide_this”,然后我们用css设置显示为none。我们从预定义的数据框num_buttons 中获取用户可以看到的按钮数量,然后将 100 除以该数字以获得每个按钮应填充的宽度。 user2 的逻辑相同

library(shiny)
library(shinyauthr)
library(shinyjs)

user_base <- tibble::tibble(
  user = c("user1", "user2", "user3"),
  password = sapply(c("pass1", "pass2", "pass3"), sodium::password_store),
  permissions = c("admin", "standard", "Basic"),
  name = c("User One", "User Two", "User Three")
)

num_buttons <- data.frame(
  user1 = 4,
  user2 = 3,
  user3 = 2
)

ui <- fluidPage(
  
  shinyjs::useShinyjs(),
  
  tags$head(
    tags$style(
      HTML('#hide_this { display: none;}')
    )
  ),
  
  tags$script(src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"),
    
  # login section
  shinyauthr::loginUI(id = "login"),
  
  # Row to add buttons after login
  fluidRow(align = 'center',
           div(id = 'add_buttons')
  )  
)

server <- function(input, output, session) {
  
  credentials <- shinyauthr::loginServer(
    id = "login",
    data = user_base,
    user_col = user,
    pwd_col = password,
    sodium_hashed = TRUE,
    log_out = reactive(logout_init())
  )
  
  # Logout to hide
  logout_init <- shinyauthr::logoutServer(
    id = "logout",
    active = reactive(credentials()$user_auth)
  )
  
  
  observe({
    if( is.null(credentials()$info$user)){
      
    }else if(credentials()$info$user == user_base$user[1]){
     
      insertUI(
        selector = "#add_buttons",
        where = "beforeEnd",
        ui = fluidRow(align = 'center',
                      column(3, id = "show_this", align="center", actionButton('b1', 'Button 1')),
                      column(3, id = "show_this", align="center", actionButton('b2', 'Button 2')),
                      column(3, id = "show_this", align="center", actionButton('b3', 'Button 3')),
                      column(3, id = "show_this", align="center", actionButton('b4', 'Button 4')))
        )
      
      
      session$onFlushed(function() {
        shinyjs::runjs(paste0('$("#show_this").width("', trunc(100/num_buttons$user1-5), '%")'))
      }, once=TRUE)
      
    }else if (credentials()$info$user == user_base$user[2]){
     
      insertUI(
        selector = "#add_buttons",
        where = "beforeEnd",
        ui = fluidRow(align = 'center',
                      column(3, id = "show_this", align="center", actionButton('b1', 'Button 1')),
                      column(3, id = "show_this", align="center", actionButton('b2', 'Button 2')),
                      column(3, id = "hide_this", align="center", actionButton('b3', 'Button 3')),
                      column(3, id = "show_this", align="center", actionButton('b4', 'Button 4')))
      )
      
# change width of shown buttons
      
      session$onFlushed(function() {
        shinyjs::runjs(paste0('$("#show_this").width("', trunc(100/num_buttons$user2), '%")'))
      }, once=TRUE)
      
    } else if (credentials()$info$user == user_base$user[3]) {
     
      insertUI(
        selector = "#add_buttons",
        where = "beforeEnd",
        ui = fluidRow(align = 'center',
                      column(3, id = "show_this", align="center", actionButton('b1', 'Button 1')),
                      column(3, id = "show_this", align="center", actionButton('b2', 'Button 2')),
                      column(3, id = "hide_this", align="center", actionButton('b3', 'Button 3')),
                      column(3, id = "hide_this", align="center", actionButton('b4', 'Button 4')))
      )
      
      
      session$onFlushed(function() {
        shinyjs::runjs(paste0('$("#show_this").width("', trunc(100/num_buttons$user3), '%")'))
      }, once=TRUE)
      
      runjs(paste0('console.log(', '"how")'))
      
   } 
  })


    # Show plot only when authenticated
#    req(credentials()$user_auth)
    

  
}

shinyApp(ui = ui, server = server)

结果:

【讨论】:

    【解决方案2】:

    一个可能的解决方案是避免使用 div 并使用 column 标签来保持容器的宽度。仅将 id 放在内部列上,其宽度应设置为 12,应该会给您想要的结果。

    library(shiny)
    library(shinyjs)
    ui <- fluidPage(
        shinyjs::useShinyjs(),
        fluidRow( align = 'center',
                  column(3, align="center", actionButton('b1', 'Button 1')),
                  column(3, align="center", actionButton('b2', 'Button 2')),
                  column(3, column(12, id = 'hide_this', align="center", actionButton('b3', 'Button 3'))),
                  column(3, align="center", actionButton('b4', 'Button 4'))
        )
    )
    
    server <- function(input, output, session) {
        shinyjs::hide('hide_this')
    }
    
    shinyApp(ui = ui, server = server)
    
    

    编辑: 我尝试了评论中建议的方法。这应该工作并根据需要间隔按钮。使用第二个按钮作为触发器(可以更改),可以根据响应式值更新 UI 元素,该响应值会根据按钮单击而更改。

    library(shiny)
    ui <- fluidPage(
        fluidRow(align = 'center',
                 uiOutput("cols")
        )
    )
    
    server <- function(input, output, session) {
        # setting reactive value
        selectview <- reactiveVal(TRUE)
        # taglist one with four buttons
        taglist1 <- tagList(
            fillRow(
                div(align="center", actionButton('b1', 'Button 1')),
                div(align="center", actionButton('b2', 'Button 2')),
                div(align="center", actionButton('b3', 'Button 3')),
                div(align="center", actionButton('b4', 'Button 4'))
            )
        )
        # taglist two with three buttons
        taglist2 <- tagList(
            fillRow(
                div(align="center", actionButton('b1', 'Button 1')),
                div(align="center", actionButton('b2', 'Button 2')),
                div(align="center", actionButton('b4', 'Button 4'))
            )
        )
        # if else statement for changing which list is displayed
        selectlist <- reactive({
            if (selectview()) {
                taglist1
            } else {
                taglist2
            }
        })
        # updating tag list
        output$cols <- renderUI({   
            selectlist()
        }) 
        # updating reactive value based on button click
        observeEvent(input$b2, {
            selectview(!selectview())
        })
    }
    
    shinyApp(ui = ui, server = server)
    

    【讨论】:

    • 感谢@Pauline,但不完全是。运行代码时,您会发现就水平间距而言,按钮 2 和 4 之间的间隙比按钮 1 和 2 之间的间隙大得多。我正在尝试使其相等。
    • 好的,现在知道了。让我回顾一下。
    猜你喜欢
    • 1970-01-01
    • 2016-02-01
    • 2014-06-10
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 2016-08-09
    • 2015-01-23
    • 2012-05-05
    相关资源
    最近更新 更多