Dhiraj
Dhiraj

Reputation: 1720

Align elements inside a fluidRow

I have a shiny app with a few elements in a fluidRow. Based on the login, I need to show/hide these elements. However, once I hide them the alignment of the elements within the fluidRow gets affected.

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)

If I hide the third button, I want the remaining buttons to align (take up the full width with even distribution) within the fluidRow. Is there some way of achieving this? I also tried fillRow and fillCol but no joy.

Upvotes: 2

Views: 2304

Answers (2)

Pauline
Pauline

Reputation: 13

A possible solution would be to avoid using div and work with column tag instead to maintain the width of the container. Having the id only on the inside column, whose width should be set to 12, should give you the desired result.

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)

Edit: I tried the approach suggested in the comment. This should work and space out the buttons as needed. Using the second button as a trigger (can be changed), it is possible to update the UI elements based on a reactive value that changes based on the button click.

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)

Upvotes: 0

Mr.Rlover
Mr.Rlover

Reputation: 2613

I am not sure how you are handling your logins so I have made my own basic example taken from the shinyauthr package. I have created 3 users, user1 can see all buttons, user2 only 3 and user3 only 2. We use insertUI() to create the buttons in the server. So we check which user has logged in, then make the row of buttons. If it's user1, all buttons are shown. If it's user2, then one button is given the id of "#hide_this", then we use css to set the display to none. We get the number of buttons that user can see from the predefined dataframe, num_buttons and divide 100 by that number to get the width that each button should fill. Same logic for 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)

Result:

enter image description here

Upvotes: 1

Related Questions