I'm trying to create unit tests for a shiny app I've been working on but can't work out how to input values for an editable DT table.
Example app:
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("table"),
textOutput("mean")
)
server <- function(input, output) {
tableUpdate <- reactiveVal(0)
table <- data.frame(A = 1:5, B = 6:10, C = 11:15)
output$table <- renderDT({table},
options = list(paging = FALSE, dom = 't'),
selection = 'none',
server = FALSE,
editable = list(target = 'row')
)
observeEvent(input$table_cell_edit, {
table <<- editData(table, input$table_cell_edit)
tableUpdate(tableUpdate() + 1)
})
output$mean <- renderText({
tableUpdate()
paste(mean(table$A), mean(table$B), mean(table$C))
})
}
shinyApp(ui, server)
Example test:
library(shinytest)
app <- ShinyDriver$new(".")
app$setInputs(table_cell_clicked = list(row = 2, col = 2, value = 7), allowInputNoBinding_ = TRUE)
app$setInputs(table_cell_edit = data.frame(row = 2, col = 0:3, value = "1"),
allowInputNoBinding_ = TRUE, priority_ = "event", wait_ = FALSE, values_ = FALSE)
app$takeScreenshot()
app$stop()
rm(app)
I've kept this mostly how it came out when I recorded the test, but I've corrected the setInputs values of table_cell_edit and table_cell_clicked (which came out as vectors).
This gives the error:
Error in sd_getAllValues(self, private, input, output, export) :
Unable to fetch all values from server. Is target app running with options(shiny.testmode=TRUE?)
Running in test mode does not fix the issue.
While experiencing the same issue, I managed to fix yours.
the mistake was here (when you are trying to update the reactive value):
tableUpdate(tableUpdate() + 1)
instead of ....
tableUpdate(table)
Please find the updated entire code below.
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput("tabled"),
textOutput("mean")
)
server <- function(input, output) {
tableUpdate <- reactiveVal(NULL)
table <- data.frame(A = 1:5, B = 6:10, C = 11:15)
output$tabled <- renderDT({table},
options = list(paging = FALSE, dom = 't'),
selection = 'none',
server = TRUE,
editable = 'row')
observeEvent(input$tabled_cell_edit, {
table<<- editData(table, input$tabled_cell_edit,'tabled')
tableUpdate(table)
a<-mean(table$A)
b<-mean(table$B)
c<-mean(table$C)
output$mean <- renderText(paste(a,b,c))
})
}
shinyApp(ui, server)
Related
I'm running two expandable rhandsontables who should always have the same number of columns and the same column headers, though the rows differ. One of the tables (myDF1 rendered in "hottable1") is the master where the user adds/deletes columns from the tabPanel() housing that table and the second table (myDF2 rendered in "hottable2") parrots the first table in terms of number of columns and column headers but is placed in a separate tabPanel() reacting to the action buttons in the first tabPanel(). The strange thing is, this linked column addition/deletion works fine when the two tables are rendered in Shiny's fluidPage() or when using Shiny's pageWithSidebar() the two tables are housed in the same tabPanel(). However, when the two tables are in separate tabPanels() (as shown in the code below), column addition works fine but the second table in tab "Slave" crashes when deleting columns from tab "Master".
I must be missing something very basic about tabPanels(). What am I doing wrong?
I've always assumed reactivity cuts across tabPanels().
Code:
library(dplyr)
library(rhandsontable)
library(shiny)
myDF1 <- data.frame('Series 1' = c(1,24,0), check.names = FALSE)
rownames(myDF1) <- c('Term A','Term B','Term C')
myDF2 <- data.frame('Series 1' = c(20,15), check.names = FALSE)
rownames(myDF2) <- c('Boy','Girl')
ui <- pageWithSidebar(
headerPanel(""),sidebarPanel(""),
mainPanel(
tabsetPanel(
tabPanel("Master table", hr(),
rHandsontableOutput('hottable1'),br(),
actionButton("addSeries", "Add", width = 80),
fluidRow(
column(2,actionButton("delSeries","Delete", width = 80)),
column(3,uiOutput("delSeries2"))
),
),
tabPanel("Slave table", hr(),rHandsontableOutput('hottable2'))
)
)
)
server <- function(input, output) {
emptyTbl1 <- reactiveVal(myDF1)
emptyTbl2 <- reactiveVal(myDF2)
observeEvent(input$hottable1, {emptyTbl1(hot_to_r(input$hottable1))})
observeEvent(input$hottable2, {emptyTbl2(hot_to_r(input$hottable2))})
output$hottable1 <- renderRHandsontable({
rhandsontable(emptyTbl1(),rowHeaderWidth = 100, useTypes = TRUE)%>%
hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
})
output$hottable2 <- renderRHandsontable({
rhandsontable(emptyTbl2(),rowHeaderWidth = 100, useTypes = TRUE)%>%
hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
})
observeEvent(input$addSeries, {
newCol1 <- data.frame(c(1,24,0))
newCol2 <- data.frame(c(20,15))
names(newCol1) <- paste("Series", ncol(hot_to_r(input$hottable1)) + 1)
names(newCol2) <- paste("Series", ncol(hot_to_r(input$hottable2)) + 1)
emptyTbl1(cbind(emptyTbl1(), newCol1))
emptyTbl2(cbind(emptyTbl2(), newCol2))
})
observeEvent(input$delSeries3, {
tmp1 <- emptyTbl1()
tmp2 <- emptyTbl2()
if(ncol(tmp1) > 1){
delCol <- input$delSeries3
tmp1 <- tmp1[ , !(names(tmp1) %in% delCol), drop = FALSE]
tmp2 <- tmp2[ , !(names(tmp2) %in% delCol), drop = FALSE]
newNames <- sprintf("Series %d",seq(1:ncol(tmp1)))
names(tmp1) <- newNames
names(tmp2) <- newNames
emptyTbl1(tmp1)
emptyTbl2(tmp2)
}
})
output$delSeries2 <-
renderUI(
selectInput("delSeries3",
label = NULL,
choices = colnames(hot_to_r(input$hottable1)),
selected = "", width = '100px',
multiple = TRUE)
)
}
shinyApp(ui,server)
The below "resolved code" resolves the issue. The few changes from OP code are commented below and are summarized as follows:
Insert outputOptions(output, 'hottable2', suspendWhenHidden = FALSE) in the server() section in order to update the 2nd table located in a separate tab panel from the action buttons driving that table from another tab panel; allows reactivity to instantly cross tab panels that aren't being viewed
Even with the above fix, the "hottable2" table had to be clicked on in order to completely render it. R whiz Stéphane Laurent pointed out that there's a known bug in Shiny when re-rendering this way, his html solution is accordingly included and commented in the revised code below for the rhandsontable() function used for "hottable2" in the server() section
Resolved code:
library(dplyr)
library(rhandsontable)
library(shiny)
myDF1 <- data.frame('Series 1' = c(1,24,0), check.names = FALSE)
rownames(myDF1) <- c('Term A','Term B','Term C')
myDF2 <- data.frame('Series 1' = c(20,15), check.names = FALSE)
rownames(myDF2) <- c('Boy','Girl')
ui <- pageWithSidebar(
headerPanel(""),sidebarPanel(""),
mainPanel(
tabsetPanel(
tabPanel("Master table", hr(),
rHandsontableOutput('hottable1'),br(),
actionButton("addSeries", "Add", width = 80),
fluidRow(
column(2,actionButton("delSeries","Delete", width = 80)),
column(3,uiOutput("delSeries2"))
),
),
tabPanel("Slave table", hr(),rHandsontableOutput('hottable2'))
)
)
)
server <- function(input, output) {
emptyTbl1 <- reactiveVal(myDF1)
emptyTbl2 <- reactiveVal(myDF2)
observeEvent(input$hottable1, {emptyTbl1(hot_to_r(input$hottable1))})
observeEvent(input$hottable2, {emptyTbl2(hot_to_r(input$hottable2))})
output$hottable1 <- renderRHandsontable({
rhandsontable(emptyTbl1(),rowHeaderWidth = 100, useTypes = TRUE)%>%
hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE) %>%
hot_cols(colWidths = 80)
})
output$hottable2 <- renderRHandsontable({
rhandsontable(emptyTbl2(),rowHeaderWidth = 100, width = 800, height = 450,useTypes = TRUE)%>%
hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE) %>%
hot_cols(colWidths = 80) %>%
# next section of html addresses issue of correcltly rendering the slave table:
htmlwidgets::onRender(
"function(el, x){
var hot = this.hot;
$('a[data-value=\"Slave table\"').on('click', function(){
setTimeout(function(){ hot.render(); }, 200);
});
}"
)
})
observeEvent(input$addSeries, {
newCol1 <- data.frame(c(1,24,0))
newCol2 <- data.frame(c(20,15))
names(newCol1) <- paste("Series", ncol(hot_to_r(input$hottable1)) + 1)
names(newCol2) <- paste("Series", ncol(hot_to_r(input$hottable2)) + 1)
emptyTbl1(cbind(emptyTbl1(), newCol1))
emptyTbl2(cbind(emptyTbl2(), newCol2))
})
observeEvent(input$delSeries3, {
tmp1 <- emptyTbl1()
tmp2 <- emptyTbl2()
if(ncol(tmp1) > 1){
delCol <- input$delSeries3
tmp1 <- tmp1[ , !(names(tmp1) %in% delCol), drop = FALSE]
tmp2 <- tmp2[ , !(names(tmp2) %in% delCol), drop = FALSE]
newNames <- sprintf("Series %d",seq(1:ncol(tmp1)))
names(tmp1) <- newNames
names(tmp2) <- newNames
emptyTbl1(tmp1)
emptyTbl2(tmp2)
}
})
output$delSeries2 <-
renderUI(
selectInput("delSeries3",
label = NULL,
choices = colnames(hot_to_r(input$hottable1)),
selected = "", width = '100px',
multiple = TRUE)
)
outputOptions(output, 'hottable2', suspendWhenHidden = FALSE) # this updates slave panel even when hidden
}
shinyApp(ui,server)
I have the following shiny app where the user can change the values of a table, however, if the user leaves an empty date field it generates an error but I don't know how to solve it.
I have tried to put the new value as as.character, as.Date, as.Posixct but it has not worked, I would appreciate any kind of guidance or help.
This is the message that the console throws:
Warning: Error in charToDate: character string is not in a standard unambiguous format
[No stack trace available]
Thank you
library(shiny)
#library(shinyjs)
library(DT)
#library(data.table)
#library(shinyalert)
#library(openxlsx)
#library(shinyFiles)
#library(dplyr)
#library(stringi)
#useShinyalert()
df <- data.frame(
Var1 = letters[1:10],
Var2 = round(rnorm(10),3),
Date1 = seq(as.Date("2000/01/01"), by = "month", length.out = 10),
Date2 = seq(as.Date("2000/01/01"), by = "month", length.out = 10)
)
d1 <- reactiveValues()
d1$Data <- df
server <- function(input, output, session){
# RENDER TABLE ----
data.tabla <- reactive({
df <- d1$Data
return(df)
})
output$df_data <- renderDataTable({
df <- datatable(
data.tabla(),
selection = 'single', editable = TRUE, rownames = FALSE,
options = list(
paging = TRUE,
# scrollX = TRUE,
searching = TRUE,
fixedColumns = TRUE,
autoWidth = TRUE,
ordering= FALSE,
dom = 'Bfrtip',
buttons = c('excel')
),
class = "display"
)
return(df)
})
observeEvent(input$df_data_cell_edit, {
d1$Data[input$df_data_cell_edit$row,
input$df_data_cell_edit$col+1] <<- input$df_data_cell_edit$value
})
}
# UI ----
ui <- fluidPage(
sidebarPanel(),
mainPanel(
DT::dataTableOutput("df_data"))
)
shinyApp(ui, server)
You should not use the global assignment operator <<- along with reactiveValues. Please try the following:
library(shiny)
library(DT)
DF <- data.frame(
Var1 = letters[1:10],
Var2 = round(rnorm(10), 3),
Date1 = seq(as.Date("2000/01/01"), by = "month", length.out = 10),
Date2 = seq(as.Date("2000/01/01"), by = "month", length.out = 10)
)
d1 <- reactiveValues(Data = DF)
server <- function(input, output, session) {
DT <- reactive({
d1$Data
})
output$df_data <- renderDataTable({
datatable(
DT(),
selection = 'single',
editable = TRUE,
rownames = FALSE,
options = list(
paging = TRUE,
# scrollX = TRUE,
searching = TRUE,
fixedColumns = TRUE,
autoWidth = TRUE,
ordering = FALSE,
dom = 'Bfrtip',
buttons = c('excel')
),
class = "display"
)
})
observeEvent(input$df_data_cell_edit, {
d1$Data[input$df_data_cell_edit$row, input$df_data_cell_edit$col + 1] <- input$df_data_cell_edit$value
})
}
ui <- fluidPage(sidebarPanel(), mainPanel(DT::dataTableOutput("df_data")))
shinyApp(ui, server)
You could check that the Date columns are in proper Date format:
library(shiny)
df <- data.frame(
Var1 = letters[1:10],
Var2 = round(rnorm(10),3),
Date1 = seq(as.Date("2000/01/01"), by = "month", length.out = 10),
Date2 = seq(as.Date("2000/01/01"), by = "month", length.out = 10)
)
d1 <- reactiveValues()
d1$Data <- df
server <- function(input, output, session){
# RENDER TABLE ----
data.tabla <- reactive({
df <- d1$Data
return(df)
})
output$df_data <- renderDataTable({
df <- datatable(
data.tabla(),
selection = 'single', editable = TRUE, rownames = FALSE,
options = list(
paging = TRUE,
# scrollX = TRUE,
searching = TRUE,
fixedColumns = TRUE,
autoWidth = TRUE,
ordering= FALSE,
dom = 'Bfrtip',
buttons = c('excel')
),
class = "display"
)
return(df)
})
observeEvent(input$df_data_cell_edit, {
value <- input$df_data_cell_edit$value
row <- input$df_data_cell_edit$row
col <- input$df_data_cell_edit$col + 1
if (col >= 3 & tryCatch({
as.Date(value); TRUE},error = function(err) {FALSE}) ) {
d1$Data[row,col] <<- input$df_data_cell_edit$value
} else {
showModal(modalDialog(
title = "Wrong date format",
"Check date format!"
))
d1$Data[row,col] <- NA
}
})
}
# UI ----
ui <- fluidPage(
sidebarPanel(),
mainPanel(
DT::dataTableOutput("df_data"))
)
shinyApp(ui, server)
I have a Shiny app with an editable DT table. Everything is working perfectly on desktop: I double click on a cell, edit the value, the value is processed in the background, and the whole table is updated appropriately.
However, on Chrome for Android double-click doesn't seem to be an option, so I can't edit the cells in my table.
After much searching for solutions, I tried to add a callback to trigger a doubleclick on a single click, but it doesn't have any effect. I give a minimal example below.
library(shiny)
library(DT)
ui <- fluidPage( mainPanel( DTOutput("table") ) )
server <- function(input, output, session) {
NumDays <- 14
DayNum <- seq_len(NumDays)
DF <- data.frame(Day=DayNum, Week=((DayNum-1) %/% 7 + 1), Steps=rep(0, NumDays), row.names=NULL)
proxy <- dataTableProxy('table')
js <- "table.on('click', 'tr', function() {
table.cell(this).trigger('dblclick.dt');
});"
output$table <- renderDT(datatable(DF, rownames = FALSE, selection = list(mode = 'none'), editable = list(target='cell'), options = list(scrollY = 600, searching = FALSE, paging=FALSE, ordering=FALSE, info=FALSE), callback = JS(js)))
proxy <- dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info <- input$table_cell_edit
i <- info$row; j <- info$col+1; v <- info$value
currentvalue <- abs(as.numeric(v))
DF[i, j] <<- currentvalue + 10
replaceData(proxy, DF, rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
I just tweaked your example with a bit jquery and got it to work - also note I changed 'tr' to 'td':
library(shiny)
library(DT)
ui <- fluidPage( mainPanel( DTOutput("table") ) )
server <- function(input, output, session) {
NumDays <- 14
DayNum <- seq_len(NumDays)
DF <- data.frame(Day=DayNum, Week=((DayNum-1) %/% 7 + 1), Steps=rep(0, NumDays), row.names=NULL)
proxy <- dataTableProxy('table')
js <- "table.on('click', 'td', function() {
$(this).dblclick();
});"
output$table <- renderDT(datatable(DF, rownames = FALSE, selection = list(mode = 'none'), editable = list(target='cell'), options = list(scrollY = 600, searching = FALSE, paging=FALSE, ordering=FALSE, info=FALSE), callback = JS(js)))
proxy <- dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info <- input$table_cell_edit
i <- info$row; j <- info$col+1; v <- info$value
currentvalue <- abs(as.numeric(v))
DF[i, j] <<- currentvalue + 10
replaceData(proxy, DF, rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
Hope this helps
edit: Here is the solution to the original problem. I found it after scouring stack and the other part, persistent filters was found on a blog. May anyone who finds this never have to suffer like I have.
source_data <-
iris %>%
mutate(Species = as.factor(Species))
source_data$Date <- Sys.time() + seq_len(nrow(source_data))
# default global search value
if (!exists("default_search")) default_search <- ""
# default column search values
if (!exists("default_search_columns")) default_search_columns <- NULL
shinyApp(
ui = fluidPage(
DT::dataTableOutput('dataTable')
),
server = function(input, output, session) {
reactive_values <- reactiveValues(source_data = NULL)
observe({
reactive_values$source_data <- source_data
})
output$dataTable <- DT::renderDataTable(
reactive_values$source_data,
editable = list(target = "cell", disable = list(columns = c(1, 2))),
filter = "top",
selection = 'none',
options = list(
scrollX = TRUE,
stateSave = FALSE,
searchCols = default_search_columns,
search = list(
regex = FALSE,
caseInsensitive = FALSE,
search = default_search
)
)
)
proxy <- dataTableProxy('dataTable')
observe({
input$dataTable_cell_edit
# when it updates, save the search strings so they're not lost
isolate({
# update global search and column search strings
default_search <- input$dataTable_search
default_search_columns <- c("", input$dataTable_search_columns)
# update the search terms on the proxy table (see below)
proxy %>%
updateSearch(keywords =
list(global = default_search,
columns = default_search_columns))
})
})
observeEvent(input$dataTable_cell_edit, {
info = input$dataTable_cell_edit
str(info)
i <- info$row
j <- info$col
v <- info$value
reactive_values$source_data[i, j] <<- DT:::coerceValue(v, reactive_values$source_data[i, j])
source_data[i, j] <<- DT:::coerceValue(v, reactive_values$source_data[i, j])
replaceData(proxy, source_data, resetPaging = FALSE, rownames = FALSE)
})
}
)
I have spent days trying to find just the right solution to this problem and while I've seen many discussions nothing quite "works" how I need it to.
I need my solution to meet these requirements;
the table is editable
There are filters that are reactive to the contents of the table
When new values are entered into the table the edits are a) saved into the data b) reflected in the filters
I've tried DT while it has the nicest looking output I couldn't get the DT filters to update and if you made an edit and filtered the table the edit would be reverted.
rHandsOnTable had a better looking edit option but same issues as above.
dqshiny, an augment for rHandsonTable enables me to save the data and it updates the filter, but the filter options weren't good, the "select" input doesn't seem let me select nothing to display all results. And because my actual data has a lot of text in each box as I horizontally scroll the height of the cells change and this makes the filters and cell widths desync.
With that said here is what I've tried, I hope someone can help me figure out
### DT that doesn't update filters but saves content
shinyApp(
ui = fluidPage(
DT::dataTableOutput('x1')
),
server = function(input, output, session) {
x = iris
x$Date = Sys.time() + seq_len(nrow(x))
output$x1 = DT::renderDataTable(x, editable = TRUE, filter = "top", selection = 'none', rownames = FALSE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col + 1
v = info$value
x[i, j] <<- DT:::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
})
}
)
dqShiny "works" but in my full dataset when I set each column's filter type something must be wrong with how it processes the data because it's discarding a lot of rows out of hand and I can't figure out why. Also can't turn off filters for specific columns. all or nothing as far as I can tell.
# library(tidyverse)
# library(shiny)
# library(rhandsontable)
# install.packages("remotes")
# library(remotes)
# remotes::install_github("daqana/dqshiny")
# library(dqshiny)
shinyApp(
ui = fluidPage(
dq_handsontable_output("randomTable", 9L)
),
server = function(input, output, session) {
hw <- c("Hello", "my", "funny", "world!")
data <- data.frame(A = rep(hw, 500), B = hw[c(2,3,4,1)],
C = 1:500, D = Sys.Date() - 0:499, stringsAsFactors = FALSE)
dq_render_handsontable(
"randomTable",
data = data,
width_align = TRUE,
filters = c("Select"),
table_param =
list(
height = 800,
readOnly = TRUE,
stretchH = "all",
highlightCol = TRUE,
highlightRow = TRUE
),
col_param =
list(
list(col = c("A", "B"), readOnly = FALSE, colWidths = "100%"),
list(col = c("C", "D"), colWidths = 300)
),
horizontal_scroll = TRUE
)
}
)
and then simple hands on table that I can't get to work even a little.
shinyApp(
ui = fluidPage(
rHandsontableOutput("randomTable")
),
server = function(input, output, session) {
hw <- c("Hello", "my", "funny", "world!")
data <- data.frame(
A = rep(hw, 500),
B = hw[c(2, 3, 4, 1)],
C = 1:500,
D = Sys.Date() - 0:499,
stringsAsFactors = FALSE
)
output$randomTable <- renderRHandsontable({
data %>%
rhandsontable(
height = 800,
readOnly = TRUE,
stretchH = "all",
colWidths = "100%"
) %>%
hot_col(c("A", "B"), readOnly = FALSE) %>%
hot_col(c("C", "D"), colWidths = 300) %>%
hot_table(highlightCol = TRUE, highlightRow = TRUE)
})
}
)
Perhaps you are looking for this
### DT updates filters
shinyApp(
ui = fluidPage(
DT::dataTableOutput('x1')
),
server = function(input, output, session) {
dfx <- reactiveValues(data=NULL)
observe({
x <- iris
x$Date = Sys.time() + seq_len(nrow(x))
dfx$data <- x
})
output$x1 = renderDT(dfx$data, editable = TRUE, filter = "top", selection = 'none', rownames = FALSE)
#proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col + 1
v = info$value
dfx$data[i, j] <<- DT:::coerceValue(v, dfx$data[i, j])
#replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
})
}
)
I want to include sparklines in a shiny DT. It works fine in the RStudio viewer but in Shiny the sparklines are not rendered. Here is a minimal example.
# dependencies
require(sparkline)
require(DT)
require(shiny)
# create data with sparklines
spark_data <- data.frame(
id = c('spark1', 'spark2'),
spark = c(
spk_chr(values = 1:3, elementId = 'spark1'),
spk_chr(values = 3:1, elementId = 'spark2')
)
)
# render in RStudio viewer (this works)
tbl <- datatable(spark_data, escape = FALSE)
spk_add_deps(tbl)
# render in Shiny (no sparklines rendered in DT)
ui <- fluidPage(
sparklineOutput("test_spark"),
dataTableOutput("tbl")
)
server <- function(input, output) {
# sparkline outside DT (works fine) - also ensures sparkline dependencies are attached
output$test_spark <- renderSparkline(sparkline(1:3))
# sparkline inside DT (does not render)
output$tbl <- renderDataTable(
expr = spark_data,
escape = FALSE
)
}
shinyApp(ui = ui, server = server)
I have modified your code to generate sparklines. I refered to this link to generate the sparklines.
require(sparkline)
require(DT)
require(shiny)
# create data
spark_data1<- data.frame(id = c('spark1', 'spark2'),
spark = c("1,2,3", "3,2,1"))
ui <- fluidPage(
sparklineOutput("test_spark"),
DT::dataTableOutput("tbl")
)
server <- function(input, output) {
line_string <- "type: 'line', lineColor: 'black', fillColor: '#ccc', highlightLineColor: 'orange', highlightSpotColor: 'orange'"
cd <- list(list(targets = 1, render = JS("function(data, type, full){ return '<span class=sparkSamples>' + data + '</span>' }")))
cb = JS(paste0("function (oSettings, json) {\n $('.sparkSamples:not(:has(canvas))').sparkline('html', { ",
line_string, " });\n}"), collapse = "")
output$tbl <- DT::renderDataTable({
dt <- DT::datatable(as.data.frame(spark_data1), rownames = FALSE, options = list(columnDefs = cd,fnDrawCallback = cb))
})
}
shinyApp(ui = ui, server = server)
Hope it helps!
Old-ish question, I know, but based on info in the question Add label to sparkline plot in datatable I think the solution is what you tried originally plus just a few lines. Here I trimmed out the parts demo-ing it works in the viewer and added just what is needed to make the sparklines work.
# dependencies
require(sparkline)
require(DT)
require(shiny)
# create data with sparklines
spark_data <- data.frame(
id = c('spark1', 'spark2'),
spark = c(
spk_chr(values = 1:3, elementId = 'spark1'),
spk_chr(values = 3:1, elementId = 'spark2')
)
)
### adding this <------------
cb <- htmlwidgets::JS('function(){debugger;HTMLWidgets.staticRender();}')
ui <- fluidPage(
### and this <------------
htmlwidgets::getDependency('sparkline'),
dataTableOutput("tbl")
)
server <- function(input, output) {
output$tbl <- renderDataTable(
expr = spark_data,
escape = FALSE,
### and this <------------
options = list(
drawCallback = cb
)
)
}
shinyApp(ui = ui, server = server)