splaisan
splaisan

Reputation: 923

get selected row from a DTedit uiOutput object in shiny

I need to capture the user selection from a DTedit table to build other tables.

I have used the input$<table>_rows_selected from a fresh DT objects but do not succeed doing it from a DTedit object.

I suspect that I need to build some intermediate object to capture the selection but cannot figure it out.

I added few lines to the DTedit demo code below to illustrate my issue.

Thanks for your help

library(shiny)
library(RSQLite)
library(DTedit); # devtools::install_github('jbryer/DTedit')

# Code modified from: https://github.com/jbryer/DTedit/blob/master/inst/shiny_demo/app.R

##### Load books data.frame as a SQLite database
conn <- dbConnect(RSQLite::SQLite(), "books.sqlite")

if(!'books' %in% dbListTables(conn)) {
    books <- read.csv('books.csv', stringsAsFactors = FALSE)
    books$Authors <- strsplit(books$Authors, ';')
    books$Authors <- lapply(books$Authors, trimws) # Strip white space
    books$Authors <- unlist(lapply(books$Authors, paste0, collapse = ';'))
    books$id <- 1:nrow(books)
    books$Date <- paste0(books$Date, '-01-01')
    dbWriteTable(conn, "books", books, overwrite = TRUE)
}

getBooks <- function() {
    res <- dbSendQuery(conn, "SELECT * FROM books")
    books <- dbFetch(res)
    dbClearResult(res)
    books$Authors <- strsplit(books$Authors, ';')
    books$Date <- as.Date(books$Date)
    books$Publisher <- as.factor(books$Publisher)
    return(books)
}

##### Callback functions.
books.insert.callback <- function(data, row) {
    query <- paste0("INSERT INTO books (id, Authors, Date, Title, Publisher) VALUES (",
                    "", max(getBooks()$id) + 1, ", ",
                    "'", paste0(data[row,]$Authors[[1]], collapse = ';'), "', ",
                    "'", as.character(data[row,]$Date), "', ",
                    "'", data[row,]$Title, "', ",
                    "'", as.character(data[row,]$Publisher), "' ",
                    ")")
    print(query) # For debugging
    dbSendQuery(conn, query)
    return(getBooks())
}

books.update.callback <- function(data, olddata, row) {
    query <- paste0("UPDATE books SET ",
                    "Authors = '", paste0(data[row,]$Authors[[1]], collapse = ';'), "', ",
                    "Date = '", as.character(data[row,]$Date), "', ",
                    "Title = '", data[row,]$Title, "', ",
                    "Publisher = '", as.character(data[row,]$Publisher), "' ",
                    "WHERE id = ", data[row,]$id)
    print(query) # For debugging
    dbSendQuery(conn, query)
    return(getBooks())
}

books.delete.callback <- function(data, row) {
    query <- paste0('DELETE FROM books WHERE id = ', data[row,]$id)
    dbSendQuery(conn, query)
    return(getBooks())
}

##### Create the Shiny server
server <- function(input, output) {
    books <- getBooks()
    dtedit(input, output,
           name = 'books',
           thedata = books,
           edit.cols = c('Title', 'Authors', 'Date', 'Publisher'),
           edit.label.cols = c('Book Title', 'Authors', 'Publication Date', 'Publisher'),
           input.types = c(Title='textAreaInput'),
           input.choices = list(Authors = unique(unlist(books$Authors))),
           view.cols = names(books)[c(5,1,3)],
           callback.update = books.update.callback,
           callback.insert = books.insert.callback,
           callback.delete = books.delete.callback)
    
    # removed the second example
    
    # added for this post using 'input$books_rows_selected' to capture the required info
    output$selectedrow <- renderPrint({
      s <- input$books_rows_selected
      cat(paste0("selected ID:", s))
      if (length(s)) {
        cat(getBooks()[s,1])
      }
    })
}

##### Create the shiny UI
ui <- fluidPage(
    h3('Books'),
    uiOutput('books'),
    verbatimTextOutput('selectedrow') # added for this post
)

shinyApp(ui = ui, server = server)

Upvotes: 1

Views: 168

Answers (1)

David Fong
David Fong

Reputation: 546

Here is a working example using a my modified version (v2.2.3+) of jbryer's DTedit:

My modified version of DTedit returns reactiveValues, including $rows_selected (only one row can be selected, though!).

library(shiny)
library(RSQLite)
library(DTedit); # devtools::install_github('DavidPatShuiFong/DTedit')

# Code modified from: https://github.com/jbryer/DTedit/blob/master/inst/shiny_demo/app.R

##### Load books data.frame as a SQLite database
conn <- dbConnect(RSQLite::SQLite(), "books.sqlite")

if(!'books' %in% dbListTables(conn)) {
    books <- read.csv('books.csv', stringsAsFactors = FALSE)
    books$Authors <- strsplit(books$Authors, ';')
    books$Authors <- lapply(books$Authors, trimws) # Strip white space
    books$Authors <- unlist(lapply(books$Authors, paste0, collapse = ';'))
    books$id <- 1:nrow(books)
    books$Date <- paste0(books$Date, '-01-01')
    dbWriteTable(conn, "books", books, overwrite = TRUE)
}

getBooks <- function() {
    res <- dbSendQuery(conn, "SELECT * FROM books")
    books <- dbFetch(res)
    dbClearResult(res)
    books$Authors <- strsplit(books$Authors, ';')
    books$Date <- as.Date(books$Date)
    books$Publisher <- as.factor(books$Publisher)
    return(books)
}

##### Callback functions.
books.insert.callback <- function(data, row) {
    query <- paste0("INSERT INTO books (id, Authors, Date, Title, Publisher) VALUES (",
                    "", max(getBooks()$id) + 1, ", ",
                    "'", paste0(data[row,]$Authors[[1]], collapse = ';'), "', ",
                    "'", as.character(data[row,]$Date), "', ",
                    "'", data[row,]$Title, "', ",
                    "'", as.character(data[row,]$Publisher), "' ",
                    ")")
    print(query) # For debugging
    dbSendQuery(conn, query)
    return(getBooks())
}

books.update.callback <- function(data, olddata, row) {
    query <- paste0("UPDATE books SET ",
                    "Authors = '", paste0(data[row,]$Authors[[1]], collapse = ';'), "', ",
                    "Date = '", as.character(data[row,]$Date), "', ",
                    "Title = '", data[row,]$Title, "', ",
                    "Publisher = '", as.character(data[row,]$Publisher), "' ",
                    "WHERE id = ", data[row,]$id)
    print(query) # For debugging
    dbSendQuery(conn, query)
    return(getBooks())
}

books.delete.callback <- function(data, row) {
    query <- paste0('DELETE FROM books WHERE id = ', data[row,]$id)
    dbSendQuery(conn, query)
    return(getBooks())
}

##### Create the Shiny server
server <- function(input, output) {
    books <- getBooks()
    my_results <- dtedit(input, output,
           name = 'books',
           thedata = books,
           edit.cols = c('Title', 'Authors', 'Date', 'Publisher'),
           edit.label.cols = c('Book Title', 'Authors', 'Publication Date', 'Publisher'),
           input.types = c(Title='textAreaInput'),
           input.choices = list(Authors = unique(unlist(books$Authors))),
           view.cols = names(books)[c(5,1,3)],
           callback.update = books.update.callback,
           callback.insert = books.insert.callback,
           callback.delete = books.delete.callback)
    
    
    output$selectedrow <- shiny::eventReactive(
        my_results$rows_selected, ignoreInit = TRUE, {
            paste0("selected ID: ", my_results$rows_selected)
    })
    
}

##### Create the shiny UI
ui <- fluidPage(
    h3('Books'),
    uiOutput('books'),
    verbatimTextOutput('selectedrow') # added for this post
)

shinyApp(ui = ui, server = server)

Anyone running this example will actually need the .csv/.sqlite file, which is available in both jbryer DTedit and in my modified version.

Upvotes: 3

Related Questions