Get Selected Row From DataTable in Shiny App
UPDATE: you can now access the selected rows using input$tableId_rows_selected
in server.R
. See here for more details.
To select a unique row, you can change the callback function of your example to this:
callback = "function(table) {
table.on('click.dt', 'tr', function() {
table.$('tr.selected').removeClass('selected');
$(this).toggleClass('selected');
Shiny.onInputChange('rows',
table.rows('.selected').data()[0][0]);
});
}"
When you click on a row,it basically removes any selected rows (they have the .selected class) and selects the row you clicked on.
I also changed the code in the Shiny.onInputChange function so that it returns the number in the first column.
R Shiny : Get data from selected row
Here is a complete example based on the Shiny example you referenced. This uses mpg
data from ggplot2
.
First, you can create a reactive
expression to determine which rows should be filtered and shown in the table. Whenever one of your input
s change, then the reactive
expression will be reevaluated. To access the filtered data, you can reference as filtered_rows()
(note the parentheses).
To get the selected rows, you can use input$table_rows_selected
since your dataTableOutput
is called table
(just append "_rows_selected"). This can be one or more than one rows, and returns row numbers (e.g., 8 in your example above). Then, to extract your data, you can use filtered_rows()[input$table_rows_selected, c("model", "trans")]
which will include model
and trans
column data for the filtered rows.
The verbatimTextOutput
and toString
simply show the results for validation and demonstration. You can use the results in another context as well.
library(shiny)
library(DT)
library(ggplot2)
ui <- fluidPage(
titlePanel("Basic DataTable"),
# Create a new Row in the UI for selectInputs
fluidRow(
column(4,
selectInput("man",
"Manufacturer:",
c("All",
unique(as.character(mpg$manufacturer))))
),
column(4,
selectInput("trans",
"Transmission:",
c("All",
unique(as.character(mpg$trans))))
),
column(4,
selectInput("cyl",
"Cylinders:",
c("All",
unique(as.character(mpg$cyl))))
)
),
# Create a new row for the table.
DT::dataTableOutput("table"),
verbatimTextOutput("text")
)
server <- function(input, output) {
# Filter data based on selections
filtered_rows <- reactive({
data <- mpg
if (input$man != "All") {
data <- data[data$manufacturer == input$man,]
}
if (input$cyl != "All") {
data <- data[data$cyl == input$cyl,]
}
if (input$trans != "All") {
data <- data[data$trans == input$trans,]
}
data
})
# Show filtered data in the datatable
output$table <- DT::renderDataTable(DT::datatable({ filtered_rows() }))
# Show selected text
output$text <- renderText({ toString(filtered_rows()[input$table_rows_selected, c("model", "trans")]) })
}
shinyApp(ui, server)
Get selected row value instead of number in shiny using DT
Something like this:
library(shiny)
library(DT)
ui <- basicPage(
mainPanel(DT::dataTableOutput('mytable')),
textOutput("selected")
)
server <- function(input, output,session) {
mydata <- reactive({mtcars})
output$mytable = DT::renderDataTable(
datatable(mydata())
)
selectedRow <- eventReactive(input$mytable_rows_selected,{
row.names(mtcars)[c(input$mytable_rows_selected)]
})
output$selected <- renderText({
selectedRow()
})
}
runApp(list(ui = ui, server = server))
Select specific row of a datatable with a shiny widget
library(shiny)
library(DT)
library(shinyWidgets)
dat <- mtcars[1:6,]
callback <- JS(
"Shiny.addCustomMessageHandler(",
" 'selectRow',",
" function(index) {",
" table.row(index - 1).select();",
" }",
");"
)
ui <- fluidPage(
br(),
DTOutput("dtable"),
br(),
fluidRow(
column(
4,
pickerInput(
"rowname",
label = "Choose a row",
choices = setNames(1:nrow(dat), rownames(dat))
)
),
column(
3,
textOutput("selectedRow")
)
)
)
server <- function(input, output, session) {
output[["dtable"]] <- renderDT({
datatable(
dat,
extensions = "Select",
selection = "none",
callback = callback,
options = list(
columnDefs = list(
list(className = "dt-center", targets = "_all")
),
select = list(style = "single")
)
)
}, server = FALSE)
output[["selectedRow"]] <- renderText({
i <- input[["dtable_rows_selected"]]
paste0(
"Selected row: ",
ifelse(is.null(i), "none", i)
)
})
observeEvent(input[["rowname"]], {
session$sendCustomMessage("selectRow", input[["rowname"]])
})
}
shinyApp(ui, server)
Shiny modules: how to access selected_rows with DT::datatables?
When working with DT:datatable function we can use built-in functionality to learn about selected rows in the UI.
The object: input$my_DT_table_rows_selected
contains the index of the selected row where my_DT_table
is the ID of the DT::datatable.
However, when working with modules, the name of the table is now different. It has a prefix which is equal to the ID used to call the module's UI function.
So if that ID is my_ID
then the table name will become: my_ID-table_name
(note the hyphen after the ID).
This can be easily verified using the developer tools in your browser (e.g. inspector in FireFox).
And the associated input object name then becomes (and we need back ticks to prevent R from interpreting the hyphen as a minus sign):
input$`my_ID-table_name_rows_selected`
Here is a very basic example with some additional learning regarding how to pass a reactive object to a module. The reactive object contains the index of the selected line. I need to pass it without parenthesis. Inside of the module_server function I refer to the reactive object with parenthesis.
UI module in ui_module.R
module_ui <- function(id) {
ns <- NS(id) # create namespace
tagList(
fluidRow(column(6, DT::dataTableOutput(ns("dt_table")))),
fluidRow(column(4, verbatimTextOutput(ns("render_selected_line"))))
)
}
Server module in server_module.R
table_server <- function(input, output, session, data) {
output$dt_table <- DT::renderDataTable(
DT::datatable(
data = data,
selection = "single"
)
)
}
selected_line_server <- function(input, output, session, data) {
output$render_selected_line <- renderText({
paste0("My selection was: ", data()) # refer to the reactive object with parenthesis
})
}
Shiny application
library(shiny)
library(dplyr)
library(DT)
source("./modules/ui_module.R")
source("./modules/server_module.R")
ui <- fluidPage(
module_ui("my_ID")
)
server = function(input, output, session) {
data <- mtcars
callModule(table_server, id = "my_ID", data = data) # data is not reactive
callModule(selected_line_server, id = "my_ID", data = selectedLine) # refer to the reactive object selectedLine without parenthesis
selectedLine <- reactive({
req(input$`my_ID-dt_table_rows_selected`)
if (is.null(input$`my_ID-dt_table_rows_selected`)) {
return(NULL)
} else {
rows_selected <- as.numeric(input$`my_ID-dt_table_rows_selected`) # we need to prefix dt_table_rows_selected with the ID of the UI function "my_ID" and a hyphen
}
})
}
shinyApp(ui = ui, server = server)
Select and display the value of a row in Shiny Datatable
A few adjustments:
- Your syntax for accessing the selected rows was off slightly. From the
data.table
documentation, the input is access with the ID passed to thedataTableOutput()
; where you wroteinput$addr_rows_selected
you actually wantinput$addressTable_rows_selected
in order to find the table rendered withDT::dataTableOutput("addressTable")
. - You are mixing output types with render types. If you want the address to be output as text (per the line
textOutput("selectedAddress")
) then you should userenderText()
rather thanDT::renderDataTable()
. - In order to render the address as text, you must take the address (components) and collapse it down to a character string, which can be done with
paste(...,collapse = ",")
library(shiny)
library(data.table)
addr <- as.data.table(read.csv("addresses.csv", header = T, stringsAsFactors = F))
names(addr) [1:4]<- c("STREET ADDRESS","CITY NAME","PROVINCE","POSTAL CODE")
ui <- fluidPage(
br(),
fluidRow(
column(12, div(DT::dataTableOutput("addressTable"), style="font-family:verdana", align="left"))
),
fluidRow(
column(4, div(textOutput("selectedAddress"), align="center"))
)
)
server <- function(input, output) {
output$addressTable <- DT::renderDataTable({addr}, server = T, selection = 'single')
output$selectedAddress <- renderText({
selectedrowindex <- input$addressTable_rows_selected
selectedrowindex <- as.numeric(selectedrowindex)
selectedrow <- paste(addr[selectedrowindex,],collapse = ", ")
selectedrow
})
}
shinyApp(ui, server)
Related Topics
Correct Positioning of Multiple Significance Labels on Dodged Groups in Ggplot
Multiple Graphs of Each Time Series
Correlation Between Na Columns
How to Use the Box-Cox Power Transformation in R
Hiding Personal Functions in R
Street Address to Geolocation Lat/Long
Change the Color of Action Button in Shiny
How to Jitter Text to Avoid Overlap in a Ggplot2 Scatterplot
Traceback() for Interactive and Non-Interactive R Sessions
How to Display a Busy Indicator in a Shiny App
Meaning of Band Width in Ggplot Geom_Smooth Lm
R: Cumulative Sum Over Rolling Date Range
How to Assign Output of Cat to an Object
How to Use 'Facet' to Create Multiple Density Plot in Ggplot
How to Extract Everything Until First Occurrence of Pattern
Faster Reading of Time Series from Netcdf
Cbind Warnings:Row Names Were Found from a Short Variable and Have Been Discarded