I tried to link the handsontable spreadsheet component to shiny, as I think the shinyIncubator/matrixInput is not sufficient in my case.
I well display the handsontable component, which data comes from server.R, but I fail to implement the javascript events triggering part to return modification of datat table.
I carefully tried to inspire from tableinput.js in matrixInput, but without success. (I am surely not a javascript guru :)
library(shiny)
library(shinyIncubator)
shinyUI(pageWithSidebar(
headerPanel("Title"),
sidebarPanel(
tags$head(
tags$script(src = "jquery.handsontable.full.js"),
tags$script(src = "shiny-handsontable.js"),
tags$link(rel="stylesheet", media="screen", href = "jquery.handsontable.full.css")
)
),
mainPanel(
#matrixInput(inputId="matrixInput",label="matrixInput",data=cars),
uiOutput("example"),
tableOutput(outputId="result")
)
))
shinyServer(function(input, output) {
output$result <- renderTable({
return(input$example)
})
output$example <- renderUI({
return(tags$div(class="handsontable",tags$script(script.data(cars,"example"))))
})
# ["2010", 5, 2905, 2867, 412, 5284]
print.line <- function(line) {
return(paste('["',paste(line,collapse='","'),'"]',sep=''))
}
# ["", "Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
# ["2009", 0, 2941, 4303, 354, 5814],
# ["2012", 2, 2422, 5399, 776, 4151]
print.data <- function(data) {
str = print.line(names(data))
for (i in 1:nrow(data))
str = paste(str,print.line(data[i,]),sep=",\n")
return(str)
}
# <script>
# var data = [
# ["", "Maserati", "Mazda", "Mercedes", "Mini", "Mitsubishi"],
# ["2009", 0, 2941, 4303, 354, 5814],
# ["2012", 2, 2422, 5399, 776, 4151]
# ];
#
# $('#example').handsontable({
# data: data,
# minRows: 5,
# minCols: 6,
# minSpareRows: 1,
# autoWrapRow: true,
# colHeaders: true,
# contextMenu: true
# });
#
# $('.ver').html($('#example').data('handsontable').version);
# </script>
script.data <- function(data,name) {
return(gsub("__name__",name,paste(sep="\n",
"var __name__ = [",
print.data(data),
" ];",
"$('#__name__').handsontable({",
" data: __name__,",
" minRows: 5,",
" minCols: 2,",
" minSpareRows: 1,",
" autoWrapRow: true,",
# " colHeaders: true,",
" contextMenu: true",
"});",
"$('.ver').html($('#__name__').data('handsontable').version);")))
}
})
var tableInputBinding = new Shiny.InputBinding();
$.extend(tableInputBinding, {
find: function(scope) {
return scope.find('table.htCore');
},
getValue: function(el) {
alert("getValue");
var data = [];
var dataTable = {};
$(el).find('tr').each(function() {
var divs = $(this).find('td');
if (divs.length) {
divs.each(function(i, div) {
if (data.length <= i) {
data.push([]);
dataTable['V' + (i+1)] = data[data.length-1];
}
data[i].push($(div));//getValidator($(div)).parseInput($(div)));
});
}
});
if (data.length > 0 && data[0].length != data[data.length-1].length) {
throw "Error retrieving data from table--data was not rectangular";
}
return data;
},
setValue: function(el) {
},
getType: function(el) {
return "matrix";
},
subscribe: function(el, callback) {
$(el).on('change.htCore', function(e) { callback(); });
},
unsubscribe: function(el) {
$(el).off('')
}
});
Shiny.inputBindings.register(tableInputBinding);
If anybody here has sufficient javascript knowledge (which may be not so rare, compared to my own skills :), I am interested in your advice...