I'm trying to load data from a CSV file using a javascript inline code and then render it in Shiny.
This is part of a much larger environment in javascript, otherwise I would simply read the file with read.csv() and render it with renderDataTable()). The CSV file is located in the www directory.
According to the browser DevTools/Console, the data is loaded in console but I get this error:
Uncaught TypeError: Shiny.setInputValue is not a function
Thus, nothing is loaded into input$mapInR and nothing is displayed.
The idea is to see, in the UI, "Reading file" and then a table with the CSV data, not just load the data in console or use read.csv("this_data.csv") to read the file. I have the latest Shiny and RStudio versions.
library(shiny)
library(DT)
ui <- fluidPage(
tags$div(
tags$html("Reading file"),
# --- [1] This part should put the result of reading 'this_data.csv' into map
tags$script(HTML("
function getData(){
return fetch('this_data.csv')
.then(response => response.text())
.then(csvString => {
// Split the csv into rows
const rows = csvString.split('\\n');
for (row of rows) {
// Split the row into each of the comma separated values
console.log(row.split(','));
}
})
} // closes getData
// getData();
var map = getData();
//console.log(map);
// --- [2] Here input$mapInR <- map, but get 'Error: Shiny.setInputValue is not a function'
Shiny.setInputValue('mapInR', map)
"))
),
# --- [4] Finally, display the table
DT::dataTableOutput("table")
)
server <- function(input, output, session) {
# --- [3] This portion gets input$mapInR and renders the table
output$table <- DT::renderDataTable({
data.frame(input$mapInR)
})
}
shinyApp(ui, server)
This is this_data.csv:
Date,Open,High,Low,Close
1/2/2007,50.03978,50.11778,49.95041,50.11778
1/3/2007,50.2305,50.42188,50.2305,50.39767
1/4/2007,50.42096,50.42096,50.26414,50.33236
1/5/2007,50.37347,50.37347,50.22103,50.33459
1/6/2007,50.24433,50.24433,50.11121,50.18112
1/9/2007,49.99489,49.99489,49.80454,49.91333
1/10/2007,49.91228,50.13053,49.91228,49.97246
1/11/2007,49.88529,50.2391,49.88529,50.2391
1 Answer 1
There are several things to address in this question.
You get the Shiny.setInputValue is not a function error because Shiny is not ready when you want to use the function. You can wait for Shiny to be ready by inserting all your javascript code in this:
$(document).on('shiny:connected', function() { //javascript });You can access the array of values and use the
Shiny.setInputValue()function directly inside the promise or else you won't be able to retrieve the promise values (as you tried withvar map = getData();).The easiest way to get data in the right format to handle it with R/Shiny is to convert the csv data to an array.
You need to transform the array to a JSON string using the
JSON.stringify()function to pass it toShiny.setInputValue(), and retrieve it in Shiny with thefromJSON()function from thejsonlitepackage.Use
req(input$mapInR)to wait until the data is loaded/converted and theinput$mapInRcreated, before rendering the table.You might need to tweak the code below if you want to use values from the table for calculations, because all columns are of character type (as you can test with the
print(str(map[,3]))line.
Here's the resulting code:
library(shiny)
library(DT)
library(jsonlite)
library(data.table)
ui <- fluidPage(
tags$div(
tags$html("Reading file"),
# --- [1] This part should put the result of reading 'this_data.csv' into map
tags$script(HTML("
$(document).on('shiny:connected', function() {
// function to convert csv data to an array
const csv2json = (str, delimiter = ',') => {
const titles = str.slice(0, str.indexOf('\\n')).split(delimiter);
const rows = str.slice(str.indexOf('\\n') + 1).split('\\n');
return rows.map(row => {
const values = row.split(delimiter);
return titles.reduce((object, curr, i) => (object[curr] = values[i], object), {})
});
};
fetch('this_data.csv')
.then(response => response.text())
.then(csvString => {
let values = csv2json(csvString, ',');
var map = JSON.stringify(values);
Shiny.setInputValue('mapInR', map);
});
})
"))
),
# --- [3] Finally, display the table
DT::dataTableOutput("table")
)
server <- function(input, output, session) {
# --- [2] This portion gets input$mapInR and renders the table
output$table <- DT::renderDataTable({
req(input$mapInR)
map <- jsonlite::fromJSON(input$mapInR)
map <- as.data.table(map)
# print(str(map[,3]))
map
})
}
shinyApp(ui, server)