R Shiny DT: How to hide columns or format table? - r

I'm trying to format my datatable output. I want to make some changes to the table format (e.g, hide the row names) and hide columns (e.g., hide gears and carb, which I use to filter the datatable). I've read through this response before, but can't seem to get it to work. Does anyone have any suggestions for me?
I've prepared reproducible code below. In a nutshell, I'm using the mtcars dataset (my actual dataset is longer). Users can set filters, and the table output will update accordingly. It's this part of the code (under server) that isn't working:
class = "display nowrap compact"
#filter = "top" # location of column filters
filter = list(position = "top")
rownames = TRUE
options = list(dom = 't',
scrollX = TRUE # allow user to scroll wide tables horizontally
)
Full code here:
library(tidyverse)
library(shiny)
library(dplyr)
library(ggplot2)
library(tidyr)
library(shinycssloaders)
library(shinythemes)
library(ggforce)
library(DT)
library(shinyWidgets)
library(shinyjs)
mtcars
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
useShinyjs(),
div(
id = "form",
fluidRow(
#Button to select gear
column(6,
pickerInput(
inputId = "gear_button", label = "Gear:", choices = c("All", unique(as.character(mtcars$gear))), options = list(`actions-box` = TRUE), multiple = FALSE
),
),
#Button to select carb ranges
column(6,
pickerInput(inputId = "carb_button", label = "Carb:", choices = c("All", unique(as.character(mtcars$carb))), options = list(`actions-box` = TRUE), multiple = FALSE
),
),
)),
actionButton("resetAll", "Reset Filters")
),
mainPanel(
DT::dataTableOutput("table")
)
),
)
server <- function(input, output, session) {
#Explore tab - table
data <- mtcars
output$table <- DT::renderDataTable(DT::datatable({
data
class = "display nowrap compact"
#filter = "top" # location of column filters
filter = list(position = "top")
rownames = TRUE
options = list(dom = 't',
scrollX = TRUE # allow user to scroll wide tables horizontally
)
if (input$gear_button != "All") {
data <- data[data$gear == input$gear_button,]
}
if (input$carb_button != "All") {
data <- data[data$carb == input$carb_button,]
}
data
}))
observeEvent(input$resetAll, {
reset("form")
})
}
shinyApp(ui, server)

We can use
options= list(columnDefs = list(list(visible = FALSE, targets = target)))
to control which columns are visible, and
target <- which(names(mtcars) %in% c("gear", "carb")) - 1
to get the position of the cols. The - 1 is because js uses 0 index instead of 1 like R.
App:
library(tidyverse)
library(shiny)
library(dplyr)
library(ggplot2)
library(tidyr)
library(shinycssloaders)
library(shinythemes)
library(ggforce)
library(DT)
library(shinyWidgets)
library(shinyjs)
mtcars
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
useShinyjs(),
div(
id = "form",
fluidRow(
# Button to select gear
column(
6,
pickerInput(
inputId = "gear_button", label = "Gear:", choices = c("All", unique(as.character(mtcars$gear))), options = list(`actions-box` = TRUE), multiple = FALSE
),
),
# Button to select carb ranges
column(
6,
pickerInput(inputId = "carb_button", label = "Carb:", choices = c("All", unique(as.character(mtcars$carb))), options = list(`actions-box` = TRUE), multiple = FALSE),
),
)
),
actionButton("resetAll", "Reset Filters")
),
mainPanel(
DT::dataTableOutput("table")
)
),
)
server <- function(input, output, session) {
# Explore tab - table
data <- mtcars
table <- reactive({
if (input$gear_button != "All") {
data <- data[data$gear == input$gear_button, ]
}
if (input$carb_button != "All") {
data <- data[data$carb == input$carb_button, ]
}
data
})
output$table <- DT::renderDataTable({
target <- which(names(table()) %in% c("gear", "carb")) - 1
datatable(table(),
class = "display nowrap compact",
filter = list(position = "top"),
rownames = FALSE,
options = list(
dom = "t",
columnDefs = list(list(visible = FALSE, targets = target)),
scrollX = TRUE
)
)
})
observeEvent(input$resetAll, {
reset("form")
})
}
shinyApp(ui, server)

Related

Filter multiple DT columns by value using shiny Checkbox groups

I am trying to filter a Data Table in a shiny app using check box inputs for multiple 'Yes'/'No' columns. I would like the filtered DT to display rows that contain 'Yes' if any of the columns are checked. I am able to filter the DT using a selectizeInput box successfully, but when I add filter_at(testData, input$char, any_vars(. == "Yes")) to renderDataTable() I get "error:.varsmust be a character/numeric vector or avars()object, not adata.frame object.".
library(dplyr)
library(ggplot2)
library(shiny)
library(DT)
library(ggrepel)
library(tidyr)
library(shinycssloaders)
library(shinythemes)
testData = data.frame(sciName = c ("aPox","bPro","aMor","eCol","mDif"),
spColor = c("Red","White","White","Red","White"),
Tall = c("No","Yes","Yes","No","Yes"),
Tolerant = c("Yes","Yes","No","No","Yes"))
ui <- fluidPage(
navbarPage("SFEI Planting Palette", theme = shinytheme("lumen"),
tabPanel("Plant Selector", fluid = TRUE,
titlePanel("Plant Selector"),
mainPanel(
fluidRow(
dataTableOutput("table"),
),
),
sidebarLayout(
sidebarPanel(
titlePanel("Site Characteristics"),
"Characteristics to Attract:",
fluidRow(column(5,
checkboxGroupInput(inputId= "char", label = h3("Checkbox group"),
choices = list("CTall", "Tolerant")))),
fluidRow(column(5,
selectizeInput(inputId = "color",
label = "Select Desired Plant Colors:",
choices = unique(testData$spColor),
multiple = TRUE
)),
),
),
mainPanel(),
)
),
tabPanel("Panel2", fluid = TRUE)
),
mainPanel()
)
server <- function(input, output) {
filtered <- reactive({
req(input$color)
filter(testData, spColor %in% input$color) %>%
#The script works without this line
filter_at(testData, input$char, any_vars(. == "Yes"))
})
output$table <- DT::renderDataTable({
DT::datatable(filtered()[,c("sciName", "spColor")],
rownames = FALSE,
filter = 'top',
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = c('copy', 'csv', 'excel')
),
class="display"
)
}, server = FALSE)
}
shinyApp(ui, server)

pickerInput from Shiny doesn't work properly when you make changes in your dataframe

I am creating an app where you can select the columns that you want to see/show and do the logarithm or sqrt to the entire dataframe. The first option (selection) is running through pickerInput and the second with checkboxInputs.
In order to show the table with your selection or your changes in the dataframe, you have to click an actionButton. The selection of the columns works perfectly but if you click one of the checkboxInput after your selection, the selection is removed and you will see all the columns again.
This is how it looks when you want to do the logarithm after your selection. The selection of the columns disappear.
This is the code:
library(shiny)
library(shinyWidgets)
library(dplyr)
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
uiOutput("picker"),
checkboxInput("play", strong("I want to play with my data"), value = FALSE),
conditionalPanel(
condition = "input.play == 1",
checkboxInput("change_log2", "Log2 transformation", value = FALSE),
checkboxInput("run_sqrt", "sqrt option", value = FALSE)),
actionButton("view", "View Selection")
),
# Show a plot of the generated distribution
mainPanel(
h2('Mydata'),
DT::dataTableOutput("table"),
)
)
)
library(shiny)
library(DT)
server <- function(session, input, output) {
data <- reactive({
mtcars
})
data1 <- reactive({
dat <- data()
if(input$change_log2){
dat <- log2(dat)
}
if(input$run_sqrt){
dat <- sqrt(dat)
}
dat
})
observeEvent(input$play, {
if(!input$play) {
updateCheckboxInput(session, "change_log2", value = FALSE)
updateCheckboxInput(session, "run_sqrt", value = FALSE)
}
})
output$picker <- renderUI({
pickerInput(inputId = 'pick',
label = 'Choose',
choices = colnames(data1()),
options = list(`actions-box` = TRUE),
multiple = T,
selected = colnames(data1())
)
})
datasetInput <- eventReactive(input$view,{
datasetInput <- data1() %>%
select(input$pick)
return(datasetInput)
})
output$table <- renderDT({
datatable(
datasetInput(),
filter="top",
rownames = FALSE,
extensions = 'Buttons',
options = list(
dom = 'Blfrtip',
buttons =
list('copy', 'print', list(
extend = 'collection',
buttons = list(
list(extend = 'csv', filename = "File", title = NULL),
list(extend = 'excel', filename = "File", title = NULL)),
text = 'Download'
))
),
class = "display"
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Does anyone know what I should do to fix this?
Thanks very much in advance
Regards
That is because your pickerInput is based on data1(), and that changes based on the checkbox selection. In fact, it should be using data(). Try this
output$picker <- renderUI({
pickerInput(inputId = 'pick',
label = 'Choose',
choices = colnames(data()),
options = list(`actions-box` = TRUE),
multiple = T,
selected = colnames(data())
)
})

Wide datatables causing scrollx to scroll back when applying filters

I am able to render a datatable in my shiny app. However, whenever there is a wide table, the horizontal scroller gets back to it's initial position when you apply filters on the columns in the back. This issue occurs with numeric columns only.
I was wondering if there is a way I can disable range-based filters (but keep the filters itself) or if there is any other workaround for this problem.
I have searched github issues and stackoveflow prior to posting this question here since I couldn't find anybody having this problem.
Here is a reproducible example along with pictures-
options(scipen = 99999) #converts the sci numbers to their regular format
library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinythemes)
library(writexl)
library(dplyr)
library(DT)
library(dplyr)
mtcars_modified <- mtcars %>% dplyr::mutate(wt_2= wt,
qsec_2 = qsec,
am_2= am,
mpg_2= mpg,
gear_2 = gear,
carb_2 = carb,
disp_2 = disp,
row_names_col= rownames(mtcars))
ui <- fluidPage(
theme = shinythemes::shinytheme("simplex"),
shinyjs::useShinyjs(), # enables javascript/jQuery enhanchments
# Create Right Side Text
navbarPage(
id = "navbar",
title= div(HTML("G<em>T</em>")),
#windowTitle = "GT",
tabPanel("Data Set Info",
materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 1,
"iris"= 2,
"mtcars_modified" = 3),
icon= icon("check"),
selected = 1,
status = "success",
animation="smooth"
),
br(),
br()
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel1", "navigation"
),
tabPanelBody(
"panel2",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel1_data')),
tabPanel("Summary", verbatimTextOutput("panel1_sum")),
tabPanel(
"Plot"
)
)
),
tabPanelBody(
"panel3",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel3_data')),
tabPanel("Summary", verbatimTextOutput("panel3_sum")),
tabPanel(
"Plot"
)
)
)
)
)
)
) ,
#resizes the navbar tabs/button
tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;
font-family: "serif";')))
)
)
server <- function(input, output, session) {
# this event hides the side panel when toggled on/off
observeEvent(input$toggleSidebar, {
shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
if(!isTRUE(input$toggleSidebar)) {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
} else {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
}
})
# here we put all the data
data_sets <- list(df1 = data.frame(),
df2= iris,
df3 = mtcars_modified)
# store current dataset in reactive so we can work with plot panels
data_to_use <- reactiveValues(name = "df", data = data.frame())
observeEvent(input$controller, {
# skip first panel since it is used to display navigation
updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
# enswure value is avilable throught selected tabSet
req(input$controller)
# get current data and df name
data_to_use$data <- data_sets[[as.numeric(input$controller)]]
data_to_use$name <- names(data_sets[as.numeric(input$controller)])
# update table and sum
output[[paste0('panel', input$controller, '_data')]] <-
DT::renderDT(server = FALSE, {
DT::datatable(data_to_use$data,
filter = 'top',
extensions = 'Buttons',
options = list(scrollY = 600,
scrollX = TRUE,
dom = '<"float-left"l><"float-right"f>rt<"row"<"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>',
lengthMenu= list(c(10, 25, 50, -1),
c('10', '25', '50','All')),
buttons = list(
list(extend = "collection", text = "Download",
filename = "data_excel",
exportOptions = list(
modifier = list(page = "all")
),
action = DT::JS("function ( e, dt, node, config ) {
Shiny.setInputValue('Download_DATA', true, {priority: 'event'});}"
)
)
),
scrollCollapse= TRUE,
lengthChange = TRUE,
widthChange= TRUE,
rownames = TRUE))})
output[[paste0('panel', input$controller, '_sum')]] <- renderPrint(summary(data_to_use$data))
})
}
#runs the app
shinyApp(ui= ui, server= server)

filter data in shiny app but keeping values in selectInput when updating table

I have an shiny app that ask the user to upload a file (a tabulated file with data), then it renders this file into a table and the user can filter some values based on numericInput, selectInput, and textAreaInput. The user has to select the filters and then press a button in order to filter the table.
There is no sequential filtering, i.e, the user can fill all the filters or just one. Every time the user choose a filter the value of the other filters get updated (selectInput inputs) and this is the behaviour I want. However, once the Filter button is pressed, I can't see the previous selection and also I can't reset the filters.
What I would like to achieve is to maintain the actual behaviour when updating the filters, i.e, once I choose a filter and press the filter button the other selectInput choices are automatically updated, BUT I want to keep track of the filters choices, so the user can see the filters he/she has selected. That was what I was expecting but everytime I press the button Filter it seems that the filter tab is rendered again.
Here is my app,
library(shiny)
library(vroom)
library(dplyr)
library(shinycssloaders)
library(shinydashboard)
library(shinydashboardPlus)
library(tidyr)
header <- dashboardHeader()
sidebar <- dashboardSidebar(width = 450,
sidebarMenu(id="tabs",
menuItem("Filtros", tabName="filtros", icon = icon("bar-chart-o")),
uiOutput("filtros")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName="filtros",
fluidRow(
column(12,dataTableOutput("tabla_julio") %>% withSpinner(color="#0dc5c1"))
)
)
)
)
ui <- dashboardPagePlus(enable_preloader = TRUE, sidebar_fullCollapse = TRUE, header, sidebar, body)
server = function(input, output, session) {
#Create the choices for sample input
vals <- reactiveValues(data=NULL)
vals$data <- iris
output$filtros <- renderUI({
datos <- vals$data
conditionalPanel("input.tabs == 'filtros'",
tagList(
div(style="display: inline-block;vertical-align:top; width: 221px;",numericInput(inputId="Sepal.Length", label="Sepal.Length", value=NA, min = NA, max = NA, step = NA)),
div(
div(style="display: inline-block;vertical-align:top; width: 224px;", selectInput(inputId = "Species", label = "Species", width = "220", choices=unique(datos$Species),
selected = NULL, multiple = TRUE, selectize = TRUE, size = NULL))
)
),
actionButton("filtrar", "Filter")
)
})
# create reactiveValues
vals <- reactiveValues(data=NULL)
vals$data <- iris
# Filter data
observeEvent(input$filtrar, {
tib <- vals$data
if (!is.na(input$Sepal.Length)){
tib <- tib %>% dplyr::filter(!Sepal.Length >= input$Sepal.Length)
print(head(tib))
} else { tib <- tib }
# Filter
if (!is.null(input$Species)){
toMatch <- paste0("\\b", input$Species, "\\b")
matches <- unique(grep(paste(toMatch,collapse="|"), tib$Species, value=TRUE))
tib <- tib %>% dplyr::filter(Species %in% matches)
} else { tib <- tib}
tib -> vals$data
print(head(tib, n=15))
})
# Reactive function creating the DT output object
output$tabla_julio <- DT::renderDataTable({
DT::datatable(vals$data)
})
}
shinyApp(ui, server)
Another Update:
library(shiny)
library(vroom)
library(dplyr)
library(shinycssloaders)
library(shinydashboard)
library(shinydashboardPlus)
library(tidyr)
header <- dashboardHeader()
sidebar <- dashboardSidebar(width = 450,
sidebarMenu(id = "tabs",
menuItem(
"Filtros",
tabName = "filtros",
icon = icon("bar-chart-o")
),
uiOutput("filtros")
))
body <- dashboardBody(tabItems(tabItem(tabName = "filtros",
fluidRow(
column(12,
DT::dataTableOutput("tabla_julio") # %>% withSpinner(color = "#0dc5c1")
)
))))
ui <-
dashboardPagePlus(
enable_preloader = FALSE,
sidebar_fullCollapse = TRUE,
header,
sidebar,
body
)
server = function(input, output, session) {
# Create the choices for sample input
vals <- reactiveValues(data = iris, filtered_data = iris)
output$filtros <- renderUI({
datos <- isolate(vals$data)
conditionalPanel(
"input.tabs == 'filtros'",
tagList(
div(
style = "display: inline-block;vertical-align:top; width: 221px;",
numericInput(
inputId = "SepalLength",
label = "Sepal.Length",
value = NA,
min = NA,
max = NA,
step = NA
)
),
div(
div(
style = "display: inline-block;vertical-align:top; width: 224px;",
selectInput(
inputId = "Species",
label = "Species",
width = "220",
choices = unique(isolate(datos$Species)),
selected = NULL,
multiple = TRUE,
selectize = TRUE,
size = NULL
)
)
)
),
actionButton("filtrar", "Filter", style = "width: 100px;"),
actionButton("reset", "Reset", style = "width: 100px;")
)
})
# Filter data
observeEvent(input$filtrar, {
tib <- vals$data
if (!is.na(input$SepalLength)) {
tib <- tib %>% dplyr::filter(Sepal.Length < input$SepalLength)
print(head(tib))
} else {
tib
}
# Filter
if (!is.null(input$Species)) {
tib <- tib %>% dplyr::filter(Species %in% input$Species)
} else {
tib
}
print(head(tib, n = 15))
vals$filtered_data <- tib
updateSelectInput(session, inputId = "Species", selected = input$Species, choices = unique(vals$filtered_data$Species))
})
observeEvent(input$reset, {
updateNumericInput(session, inputId = "SepalLength", value = NA)
updateSelectInput(session, inputId = "Species", selected = "")
})
# Reactive function creating the DT output object
output$tabla_julio <- DT::renderDataTable({
DT::datatable(vals$filtered_data)
}, server = FALSE)
}
shinyApp(ui, server)
Update: Here is what I think you are after. The most important step is to isolate the inputs in renderUI so they aren't re-rendered on every input change.
library(shiny)
library(vroom)
library(dplyr)
library(shinycssloaders)
library(shinydashboard)
library(shinydashboardPlus)
library(tidyr)
header <- dashboardHeader()
sidebar <- dashboardSidebar(width = 450,
sidebarMenu(id = "tabs",
menuItem(
"Filtros",
tabName = "filtros",
icon = icon("bar-chart-o")
),
uiOutput("filtros")
))
body <- dashboardBody(tabItems(tabItem(tabName = "filtros",
fluidRow(
column(12,
DT::dataTableOutput("tabla_julio") # %>% withSpinner(color = "#0dc5c1")
)
))))
ui <-
dashboardPagePlus(
enable_preloader = FALSE,
sidebar_fullCollapse = TRUE,
header,
sidebar,
body
)
server = function(input, output, session) {
# Create the choices for sample input
vals <- reactiveValues(data = iris, filtered_data = iris)
output$filtros <- renderUI({
datos <- isolate(vals$data)
conditionalPanel(
"input.tabs == 'filtros'",
tagList(
div(
style = "display: inline-block;vertical-align:top; width: 221px;",
numericInput(
inputId = "SepalLength",
label = "Sepal.Length",
value = NA,
min = NA,
max = NA,
step = NA
)
),
div(
div(
style = "display: inline-block;vertical-align:top; width: 224px;",
selectInput(
inputId = "Species",
label = "Species",
width = "220",
choices = unique(isolate(datos$Species)),
selected = NULL,
multiple = TRUE,
selectize = TRUE,
size = NULL
)
)
)
),
actionButton("filtrar", "Filter", style = "width: 100px;"),
actionButton("reset", "Reset", style = "width: 100px;")
)
})
# Filter data
observeEvent(input$filtrar, {
tib <- vals$data
if (!is.na(input$SepalLength)) {
tib <- tib %>% dplyr::filter(Sepal.Length < input$SepalLength)
print(head(tib))
} else {
tib
}
# Filter
if (!is.null(input$Species)) {
tib <- tib %>% dplyr::filter(Species %in% input$Species)
} else {
tib
}
print(head(tib, n = 15))
vals$filtered_data <- tib
})
observeEvent(input$reset, {
updateNumericInput(session, inputId = "SepalLength", value = NA)
updateSelectInput(session, inputId = "Species", selected = "")
})
# Reactive function creating the DT output object
output$tabla_julio <- DT::renderDataTable({
DT::datatable(vals$filtered_data)
}, server = FALSE)
}
shinyApp(ui, server)
Initial answer:
I'd recommend using the selectizeGroup-module from library(shinyWidgets).
It creates a
Group of mutually dependent selectizeInput for filtering
data.frame's columns (like in Excel).
Besides the fact, that it only uses selectizeInput it seems to meet your requirements and saves us from a lot of typing.
Here is an example using the iris dataset:
library(shiny)
library(DT)
library(shinyWidgets)
library(datasets)
DF <- iris
names(DF) <- gsub("\\.", "", names(DF))
ui <- fluidPage(
fluidRow(
column(width = 10, offset = 1, tags$h3("Filter data with selectize group")),
column(width = 3, offset = 1,
selectizeGroupUI(
id = "my-filters",
params = list(
SepalLength = list(inputId = "SepalLength", title = "SepalLength:"),
SepalWidth = list(inputId = "SepalWidth", title = "SepalWidth:"),
PetalLength = list(inputId = "PetalLength", title = "PetalLength:"),
PetalWidth = list(inputId = "PetalWidth", title = "PetalWidth:"),
species = list(inputId = "Species", title = "Species:")
),
inline = FALSE
)),
column(
width = 10, offset = 1,DT::dataTableOutput(outputId = "table")
)
)
)
server <- function(input, output, session) {
filtered_table <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = DF,
vars = names(DF),
inline = FALSE
)
output$table <- DT::renderDataTable(filtered_table())
}
shinyApp(ui, server)
If i understand your question correctly, you are almost at your goal. In this case, you are overwriting your data at run-time. This causes the filter to be invalid, and the reactive UI seems to check this at every click.
A simple solution is to store the original and filtered datasets separately. An alternativ is to store the filters in a reactive-value and re-render the DataTable at run-time, using the filters on the original table. Here I'll go for the first example.
Below I've changed the following:
Added data_print and filters as reactive values for printing and filters
Changed the filtering method for filtrar, making use of data_print, and added some formatting and changed a few lines of code, as an example of code that might be easier to adapt to a given user-input
removed some unnecesary code (renderDataTable changed input to DT automatically)
server = function(input, output, session) {
#Create the choices for sample input
vals <- reactiveValues(
#raw data
data = iris,
#Exists only in order to print.
data_print = iris,
#for filtering data
filters = list(Species = c(),
Sepal.Length = c()
)
)
#in case of many filters, or filters expanding depending on input data, it might be worth adding this to reactiveValues
## Unchanged
output$filtros <- renderUI({
datos <- vals$data
conditionalPanel("input.tabs == 'filtros'",
tagList(
div(style="display: inline-block;vertical-align:top; width: 221px;",
numericInput(inputId="Sepal.Length", label="Sepal.Length",
value=NA, min = NA, max = NA, step = NA)),
div(
div(style="display: inline-block;vertical-align:top; width: 224px;",
selectInput(inputId = "Species", label = "Species", width = "220",
choices=unique(datos$Species),
selected = NULL, multiple = TRUE, selectize = TRUE, size = NULL))
)
),
actionButton("filtrar", "Filter")
)
})
# Filter data
observeEvent(input$filtrar, {
nm <- names(vals$filters)
for(i in nm){
if(is.na(input[[i]]) || is.null(input[[i]]))
vals$filters[[i]] <- unique(vals$data[[i]]) #If unfiltered use all values
else
vals$filters[[i]] <- input[[i]] #if filtered choose the filtered value
}
#Overwrite data_print instead of data. Creds to https://stackoverflow.com/a/47171513/10782538
vals$data_print <- vals$data %>% dplyr::filter((!!as.symbol(nm[1])) %in% vals$filters[[1]],
(!!as.symbol(nm[2]) %in% vals$filters[[2]]))
})
# Reactive function creating the DT output object
output$tabla_julio <- DT::renderDataTable(
vals$data_print #<====renderDataTable changes to data.
)
}

Count of selected rows is not updated correctly in a DT datatable

I have a simple shiny app
#ui.r
navbarPage(
"Application",
tabPanel("General",
sidebarLayout(
sidebarPanel(
uiOutput("tex2")
),
mainPanel(
DT::dataTableOutput("hot3")
)
)))
#server.r
library(shiny)
library(DT)
library(tidyverse)
server <- function(input, output,session) {
output$tex2<-renderUI({
numericInput("text2","Rows selected",
value = input$hot3_rows_selected,
min=0
)
})
output$hot3 <-DT::renderDataTable(
iris %>% rowid_to_column("Row") %>% mutate(Row = ""),
rownames = FALSE,
extensions = "Select",
options = list(
columnDefs = list(list(className = "select-checkbox", targets = 0, orderable = FALSE)),
select = list(style = "multi", selector = "td:first-child")
))
}
I have a numericInput() which should normally display the count of rows selected in the datatable but as you will see it displays only the first row selected and not the count of them.
To show the count of rows selected you need the length of input$hot3_rows_selected (use length(input$hot3_rows_selected) instead).
library(shiny)
ui <- navbarPage(
"Application",
tabPanel("General",
sidebarLayout(
sidebarPanel(uiOutput("tex2")),
mainPanel(DT::dataTableOutput("hot3"))
)
)
)
server <- function(input, output,session) {
library(tidyverse)
output$tex2 <- renderUI({
numericInput("text2", "Rows selected",
value = length(input$hot3_rows_selected),
min = 0)
})
output$hot3 <- DT::renderDataTable(
iris %>%
rowid_to_column("Row") %>%
mutate(Row = ""),
rownames = FALSE,
extensions = "Select",
options = list(
columnDefs = list(list(className = "select-checkbox", targets = 0, orderable = FALSE)),
select = list(style = "multi", selector = "td:first-child")
)
)
}
shinyApp(ui, server)

Resources