selectize.js and Shiny : select choices from a remote API - r

With no prior programming knowledge in JavaScript and APIs, I'm having some troubles to make this example fit my needs : select GitHub repo.
I'm trying to adapt it to work with this API: https://api-adresse.data.gouv.fr/search/? .
The response is a GeoJSON file, where the features are stored in response$features. I want to get the properties$label attribute for each feature.
Here is what I've done so far. I get an array but the items are not displayed in the dropdown...
UI :
########
# ui.R #
########
library(shiny)
fluidPage(
title = 'Selectize examples',
mainPanel(
selectizeInput('addresses', 'Select address', choices = '', options = list(
valueField = 'properties.label',
labelField = 'properties.label',
searchField = 'properties.label',
options = list(),
create = FALSE,
render = I("
{
option: function(item, escape) {
return '<div>' + '<strong>' + escape(item.properties.name) + '</strong>' + '</div>';
}
}" ),
load = I("
function(query, callback) {
if (!query.length) return callback();
$.ajax({
url: 'https://api-adresse.data.gouv.fr/search/?',
type: 'GET',
data: {
q: query
},
dataType: 'json',
error: function() {
callback();
},
success: function(res) {
console.log(res.features);
callback(res.features);
}
});
}"
)
))
)
)
Server :
############
# server.R #
############
library(shiny)
function(input, output) {
output$github <- renderText({
paste('You selected', if (input$github == '') 'nothing' else input$github,
'in the Github example.')
})
}
Thank you for your help.

Got it working thanks to this comment.
selectize doesn't support accessing nested values with dot notation
UI:
########
# ui.R #
########
library(shiny)
fluidPage(
title = 'Selectize examples',
mainPanel(
selectizeInput('addresses', 'Select address', choices = '', options = list(
valueField = 'name',
labelField = 'name',
searchField = 'name',
loadThrottle = '500',
persist = FALSE,
options = list(),
create = FALSE,
render = I("
{
option: function(item, escape) {
return '<div>' + '<strong>' + escape(item.name) + '</strong>' + '</div>';
}
}" ),
load = I("
function(query, callback) {
if (!query.length) return callback();
$.ajax({
url: 'https://api-adresse.data.gouv.fr/search/?',
type: 'GET',
data: {
q: query
},
dataType: 'json',
error: function() {
callback();
},
success: function (data) {
callback(data.features.map(function (item) {
return {name: item.properties.name,
label: item.properties.label,
score: item.properties.score};
}));
}
});
}"
)
))
)
)
Server:
############
# server.R #
############
library(shiny)
function(input, output) {
output$github <- renderText({
paste('You selected', if (input$github == '') 'nothing' else input$github,
'in the Github example.')
})
}

Related

Display a folder structure in shiny app body as a box not a pop-up

I would like to have a box in my shiny app, which user can browse to a folder structure and select a file to download.
I have tried the shinyFiles but the file selection is a pop-up window and I could just download a single file :
library(shiny)
library(shinyFiles)
ui <- fluidPage(
shinyFilesButton('files', label='File select', title='Please select a file', multiple=T) ,
verbatimTextOutput('rawInputValue'),
verbatimTextOutput('filepaths') ,
downloadButton("downloadFiles", "Download Files")
)
server <- function(input, output) {
roots = c(wd = 'H:/')
shinyFileChoose(input, 'files',
roots = roots,
filetypes=c('', 'txt' , 'gz' , 'md5' , 'pdf' , 'fasta' , 'fastq' , 'aln'))
output$rawInputValue <- renderPrint({str(input$files)})
output$filepaths <- renderPrint({parseFilePaths(roots, input$files)})
output$downloadFiles <- downloadHandler(
filename = function() {
as.character(parseFilePaths(roots, input$files)$name)
},
content = function(file) {
fullName <- as.character(parseFilePaths(roots, input$files)$datapath)
file.copy(fullName, file)
}
)
}
shinyApp(ui = ui , server = server)
What I would like is to have the file selection option like
within the ui, not as new (pop-up) window !
Here is a first version of the app I talked about in my comment. Its advantage is that the contents of a folder are loaded only when the user selects this folder, and only the first descendants are loaded, no recursion.
App folder structure:
C:\PATH\TO\MYAPP
| global.R
| server.R
| ui.R
|
\---www
navigator.css
navigator.js
File global.R:
library(shiny)
library(jsTreeR)
library(htmlwidgets)
library(magrittr)
library(shinyFiles)
roots <- c(wd = "C:/SL/MyPackages/", getVolumes()())
File server.R:
shinyServer(function(input, output, session){
shinyDirChoose(
input, "rootfolder", roots = roots,
allowDirCreate = FALSE, defaultRoot = "wd"
)
RootFolder <- eventReactive(input[["rootfolder"]], {
parseDirPath(roots, input[["rootfolder"]])
})
output[["choice"]] <- reactive({
isTruthy(RootFolder())
})
outputOptions(output, "choice", suspendWhenHidden = FALSE)
output[["navigator"]] <- renderJstree({
req(isTruthy(RootFolder()))
jstree(
nodes = list(
list(
text = RootFolder(),
type = "folder",
children = FALSE,
li_attr = list(
class = "jstree-x"
)
)
),
types = list(
folder = list(
icon = "fa fa-folder gold"
),
file = list(
icon = "far fa-file red"
)
),
checkCallback = TRUE,
theme = "default",
checkboxes = TRUE,
search = TRUE,
selectLeavesOnly = TRUE
) %>% onRender("function(el, x){tree = $(el).jstree(true);}")
})
observeEvent(input[["path"]], {
lf <- list.files(input[["path"]], full.names = TRUE)
fi <- file.info(lf, extra_cols = FALSE)
x <- list(
elem = as.list(basename(lf)),
folder = as.list(fi[["isdir"]])
)
session$sendCustomMessage("getChildren", x)
})
Paths <- reactive({
vapply(
input[["navigator_selected_paths"]], `[[`,
character(1L), "path"
)
})
output[["selections"]] <- renderPrint({
cat(Paths(), sep = "\n")
})
output[["dwnld"]] <- downloadHandler(
filename = "myfiles.zip",
content = function(file){
zip(file, files = Paths())
}
)
})
File ui.R:
shinyUI(fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "navigator.css"),
tags$script(src = "navigator.js")
),
br(),
conditionalPanel(
condition = "!output.choice",
fluidRow(
column(
width = 12,
shinyDirButton(
"rootfolder",
label = "Browse to choose a root folder",
title = "Choose a folder",
buttonType = "primary",
class = "btn-block"
)
)
)
),
conditionalPanel(
condition = "output.choice",
style = "display: none;",
fluidRow(
column(
width = 6,
jstreeOutput("navigator")
),
column(
width = 6,
tags$fieldset(
tags$legend(
tags$h1("Selections:", style = "float: left;"),
downloadButton(
"dwnld",
class = "btn-primary btn-lg",
icon = icon("save"),
style = "float: right;"
)
),
verbatimTextOutput("selections")
)
)
)
)
))
File navigator.css:
.jstree-default .jstree-x.jstree-closed > .jstree-icon.jstree-ocl,
.jstree-default .jstree-x.jstree-leaf > .jstree-icon.jstree-ocl {
background-position: -100px -4px;
}
.red {
color: red;
}
.gold {
color: gold;
}
.jstree-proton {
font-weight: bold;
}
.jstree-anchor {
font-size: medium;
}
File navigator.js:
var tree;
$(document).ready(function () {
var Children = null;
Shiny.addCustomMessageHandler("getChildren", function (x) {
Children = x;
});
$("#navigator").on("click", "li.jstree-x > i", function (e) {
var $li = $(this).parent();
if (!$li.hasClass("jstree-x")) {
alert("that should not happen...");
return;
}
var id = $li.attr("id");
var node = tree.get_node(id);
if (tree.is_leaf(node) && node.original.type === "folder") {
var path = tree.get_path(node, "/");
Shiny.setInputValue("path", path);
var interval = setInterval(function () {
if (Children !== null) {
clearInterval(interval);
for (var i = 0; i < Children.elem.length; i++) {
var isdir = Children.folder[i];
var newnode = tree.create_node(id, {
text: Children.elem[i],
type: isdir ? "folder" : "file",
children: false,
li_attr: isdir ? { class: "jstree-x" } : null
});
}
Children = null;
setTimeout(function () {
tree.open_node(id);
}, 10);
}
}, 100);
}
});
});
(I am the author of jsTreeR and I think I will do a Shiny module for this folder navigator and include it in the package.)
EDIT
I improved the app and it uses the proton theme now, which looks more pretty to me:
To use this app, you first need the updated version of the package:
remotes::install_github("stla/jsTreeR")
There are some changes in three files:
server.R:
shinyServer(function(input, output, session){
shinyDirChoose(
input, "rootfolder", roots = roots,
allowDirCreate = FALSE, defaultRoot = "wd"
)
RootFolder <- eventReactive(input[["rootfolder"]], {
parseDirPath(roots, input[["rootfolder"]])
})
output[["choice"]] <- reactive({
isTruthy(RootFolder())
})
outputOptions(output, "choice", suspendWhenHidden = FALSE)
output[["navigator"]] <- renderJstree({
req(isTruthy(RootFolder()))
jstree(
nodes = list(
list(
text = RootFolder(),
type = "folder",
children = FALSE,
li_attr = list(
class = "jstree-x"
)
)
),
types = list(
folder = list(
icon = "fa fa-folder gold"
),
file = list(
icon = "far fa-file red"
)
),
checkCallback = TRUE,
theme = "proton",
checkboxes = TRUE,
search = TRUE,
selectLeavesOnly = TRUE
)
})
observeEvent(input[["path"]], {
lf <- list.files(input[["path"]], full.names = TRUE)
fi <- file.info(lf, extra_cols = FALSE)
x <- list(
elem = as.list(basename(lf)),
folder = as.list(fi[["isdir"]])
)
session$sendCustomMessage("getChildren", x)
})
Paths <- reactive({
vapply(
input[["navigator_selected_paths"]], `[[`,
character(1L), "path"
)
})
output[["selections"]] <- renderPrint({
cat(Paths(), sep = "\n")
})
output[["dwnld"]] <- downloadHandler(
filename = "myfiles.zip",
content = function(file){
zip(file, files = Paths())
}
)
})
navigator.css:
.jstree-proton {
font-weight: bold;
}
.jstree-anchor {
font-size: medium;
}
.jstree-proton .jstree-x.jstree-closed > .jstree-icon.jstree-ocl,
.jstree-proton .jstree-x.jstree-leaf > .jstree-icon.jstree-ocl {
background-position: -101px -5px;
}
.jstree-proton .jstree-checkbox.jstree-checkbox-disabled {
background-position: -37px -69px;
}
.red {
color: red;
}
.gold {
color: gold;
}
navigator.js:
$(document).ready(function () {
var tree;
var Children = null;
Shiny.addCustomMessageHandler("getChildren", function (x) {
Children = x;
});
$navigator = $("#navigator");
$navigator.one("ready.jstree", function (e, data) {
tree = data.instance;
tree.disable_checkbox("j1_1");
tree.disable_node("j1_1");
});
$navigator.on("after_open.jstree", function (e, data) {
tree.enable_checkbox(data.node);
tree.enable_node(data.node);
});
$navigator.on("after_close.jstree", function (e, data) {
tree.disable_checkbox(data.node);
tree.disable_node(data.node);
});
$navigator.on("click", "li.jstree-x > i", function (e) {
var $li = $(this).parent();
if (!$li.hasClass("jstree-x")) {
alert("that should not happen...");
return;
}
var id = $li.attr("id");
var node = tree.get_node(id);
if (tree.is_leaf(node) && node.original.type === "folder") {
var path = tree.get_path(node, "/");
Shiny.setInputValue("path", path);
var interval = setInterval(function () {
if (Children !== null) {
clearInterval(interval);
for (var i = 0; i < Children.elem.length; i++) {
var isdir = Children.folder[i];
var newnode = tree.create_node(id, {
text: Children.elem[i],
type: isdir ? "folder" : "file",
children: false,
li_attr: isdir ? { class: "jstree-x" } : null
});
if (isdir) {
tree.disable_checkbox(newnode);
tree.disable_node(newnode);
}
}
Children = null;
setTimeout(function () {
tree.open_node(id);
}, 10);
}
}, 100);
}
});
});
EDIT 2
The new version of the package provides a Shiny module allowing to conveniently renders such a 'tree navigator' (or even several ones). This is the example given in the package:
library(shiny)
library(jsTreeR)
css <- HTML("
.flexcol {
display: flex;
flex-direction: column;
width: 100%;
margin: 0;
}
.stretch {
flex-grow: 1;
height: 1px;
}
.bottomright {
position: fixed;
bottom: 0;
right: 15px;
min-width: calc(50% - 15px);
}
")
ui <- fixedPage(
tags$head(
tags$style(css)
),
class = "flexcol",
br(),
fixedRow(
column(
width = 6,
treeNavigatorUI("explorer")
),
column(
width = 6,
tags$div(class = "stretch"),
tags$fieldset(
class = "bottomright",
tags$legend(
tags$h1("Selections:", style = "float: left;"),
downloadButton(
"dwnld",
class = "btn-primary btn-lg",
style = "float: right;",
icon = icon("save")
)
),
verbatimTextOutput("selections")
)
)
)
)
server <- function(input, output, session){
Paths <- treeNavigatorServer(
"explorer", rootFolder = getwd(),
search = list( # (search in the visited folders only)
show_only_matches = TRUE,
case_sensitive = TRUE,
search_leaves_only = TRUE
)
)
output[["selections"]] <- renderPrint({
cat(Paths(), sep = "\n")
})
}
shinyApp(ui, server)

Running JS Commands on a Shiny Markdown Document

I am trying to implement Stephane Laurent's solution to requiring a minimum number of selections for a picker input in a Shiny Markdown document but cannot figure out how to run the java script component. Can anyone tell me where I place the js and tags$head... objects to make this run correctly?
Solution Using a Traditional Shiny App
library(shiny)
library(shinyWidgets)
js <- "
$(document).ready(function(){
$('#somevalue').on('show.bs.select', function(){
$('a[role=option]').on('click', function(e){
var selections = $('#somevalue').val();
if(selections.length === 1 && $(this).hasClass('selected')){
e.stopImmediatePropagation();
};
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});"
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
pickerInput(
inputId = "somevalue",
label = "A label",
choices = c("a", "b"),
selected = "a",
multiple = TRUE
),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderPrint(input$somevalue)
}
shinyApp(ui, server)
Shiny Markdown Document Wrapper Doesn't Work
---
runtime: shiny
output:
html_document
---
```{r echo = F, message = F, warning = F, error = F}
library(shiny)
library(shinyWidgets)
js <- "
$(document).ready(function(){
$('#somevalue').on('show.bs.select', function(){
$('a[role=option]').on('click', function(e){
var selections = $('#somevalue').val();
if(selections.length === 1 && $(this).hasClass('selected')){
e.stopImmediatePropagation();
};
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});"
tags$head(tags$script(HTML(js)))
pickerInput(
inputId = "somevalue",
label = "A label",
choices = c("a", "b"),
selected = "a",
multiple = TRUE
)
```
I have not tried, but I think you can include a JavaScript chunk:
```{js}
$(document).ready(function(){
$('#somevalue').on('show.bs.select', function(){
$('a[role=option]').on('click', function(e){
var selections = $('#somevalue').val();
if(selections.length === 1 && $(this).hasClass('selected')){
e.stopImmediatePropagation();
};
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});
```

If statement treats the condition as FALSE although the condition prints out as TRUE

I am creating a shiny app, which will show modal only when a user visits the app for the first time. After the first time, modal will not be shown. However, this does not work and modal is shown in every visit.
First I set a session ID as cookies and then tried to put modal inside if statement so that if the session ID is present and equal to what I set, it will not be executed. Although the statement in if condition is FALSE, the modal is still shown. In addition, if I write FALSE inside if condition manually, it works and doesn't show the modal. I used textOutput to show if the condition is TRUE or FALSE and it shows the opposite of how if statement is behaving.
I have also tried to set only input$jscookie != sessionid as condition, but it gives Error in if: argument is of length zero error although it prints FALSE when I use same statement in textOutput({input$jscookie != sessionid}).
Below is a reproducible example showing what I'm experiencing. Thank you in advance.
library(shiny)
library(shinyjs)
if (!dir.exists('www/')) {
dir.create('www')
}
download.file(
url = 'https://github.com/js-cookie/js-cookie/releases/download/v2.2.1/js.cookie-2.2.1.min.js',
destfile = 'www/js.cookie.js'
)
sessionid <- "OQGYIrpOvV3KnOpBSPgOhqGxz2dE5A9IpKhP6Dy2kd7xIQhLjwYzskn9mIhRAVHo29"
addResourcePath("js", "www")
jsCode <- '
shinyjs.getcookie = function(params) {
var cookie = Cookies.get("id");
if (typeof cookie !== "undefined") {
Shiny.onInputChange("jscookie", cookie);
} else {
var cookie = "";
Shiny.onInputChange("jscookie", cookie);
}
}
shinyjs.setcookie = function(params) {
Cookies.set("id", escape(params), { expires: 0.5 });
Shiny.onInputChange("jscookie", params);
}
shinyjs.rmcookie = function(params) {
Cookies.remove("id");
Shiny.onInputChange("jscookie", "");
}
'
ui <- fluidPage(
tags$head(
tags$script(src = "js/js.cookie.js")
),
useShinyjs(),
extendShinyjs(text = jsCode),
textOutput('id'),
verbatimTextOutput('sometext')
)
server <- function(input, output) {
observeEvent("", {
js$getcookie()
if (is.null(input$jscookie) || input$jscookie != sessionid) {
showModal(modalDialog(
"Click close button",
easyClose = TRUE,
footer = tagList(
actionButton(inputId = "close", label = "Close", icon = icon("close"))
)
))
}
})
observeEvent(input$close,{
removeModal()
js$setcookie(sessionid)
})
sometext<-reactive({
is.null(input$jscookie) || input$jscookie != sessionid
})
output$id<-renderText({
paste('session ID:', input$jscookie)
})
output$sometext<-renderText({
sometext()
})
}
shinyApp(ui = ui, server = server)
Ok, I've solved it.
Using input$jscookie as statement in observeEvent and putting js$getcookie() outside of observeEvent solved the problem.
library(shiny)
library(shinyjs)
if (!dir.exists('www/')) {
dir.create('www')
}
download.file(
url = 'https://github.com/js-cookie/js-cookie/releases/download/v2.2.1/js.cookie-2.2.1.min.js',
destfile = 'www/js.cookie.js'
)
sessionid <- "OQGYIrpOvV3KnOpBSPgOhqGxz2dE5A9IpKhP6Dy2kd7xIQhLjwYzskn9mIhRAVHo291"
addResourcePath("js", "www")
jsCode <- '
shinyjs.getcookie = function(params) {
var cookie = Cookies.get("id");
if (typeof cookie !== "undefined") {
Shiny.onInputChange("jscookie", cookie);
} else {
var cookie = "";
Shiny.onInputChange("jscookie", cookie);
}
}
shinyjs.setcookie = function(params) {
Cookies.set("id", escape(params), { expires: 0.5 });
Shiny.onInputChange("jscookie", params);
}
shinyjs.rmcookie = function(params) {
Cookies.remove("id");
Shiny.onInputChange("jscookie", "");
}
'
ui <- fluidPage(
tags$head(
tags$script(src = "js/js.cookie.js")
),
useShinyjs(),
extendShinyjs(text = jsCode),
textOutput('id'),
verbatimTextOutput('sometext')
)
server <- function(input, output) {
js$getcookie()
observeEvent(input$jscookie, {
if (is.null(input$jscookie) || input$jscookie != sessionid) {
showModal(modalDialog(
"Click close button",
easyClose = TRUE,
footer = tagList(
actionButton(inputId = "close", label = "Close", icon = icon("close"))
)
))
}
})
observeEvent(input$close,{
removeModal()
js$setcookie(sessionid)
})
sometext<-reactive({
is.null(input$jscookie) || input$jscookie != sessionid
})
output$id<-renderText({
paste('session ID:', input$jscookie)
})
output$sometext<-renderText({
sometext()
})
}
shinyApp(ui = ui, server = server)

Shiny searchInput

Does anyone know if it is possible to create a "shinyWidget :: searchInput" designed with a grid that would allow entering only 9 digits in the field?
https://pasteboard.co/J3mduIS.png
Here is a shiny implementation of bootstrap-pincode-input.
Download the files bootstrap-pincode-input.js and bootstrap-pincode-input.css from here. Put them in the www subfolder of the folder containing the shiny app.
Also add the JS file below to the www subfolder, call it pincodeBinding.js.
var pincodeBinding = new Shiny.InputBinding();
$.extend(pincodeBinding, {
find: function (scope) {
return $(scope).find(".pincode");
},
getValue: function (el) {
return $(el).val();
},
setValue: function(el, value) {
$(el).val(value);
},
subscribe: function (el, callback) {
$(el).on("change.pincodeBinding", function (e) {
callback();
});
},
unsubscribe: function (el) {
$(el).off(".pincodeBinding");
},
initialize: function(el) {
var $el = $(el);
$el.pincodeInput({
inputs: $el.data("ndigits"),
hidedigits: $el.data("hide"),
complete: function(value, e, errorElement){
Shiny.setInputValue($el.attr("id"), value);
}
});
}
});
Shiny.inputBindings.register(pincodeBinding);
Now, the shiny app:
library(shiny)
pincodeInput <- function(inputId, width = "30%", height = "100px",
label = NULL, ndigits = 4, hideDigits = FALSE){
tags$div(style = sprintf("width: %s; height: %s;", width, height),
shiny:::shinyInputLabel(inputId, label),
tags$input(id = inputId, class = "pincode", type = "text",
`data-ndigits` = ndigits,
`data-hide` = ifelse(hideDigits, "true", "false")
)
)
}
ui <- fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "bootstrap-pincode-input.css"),
tags$script(src = "bootstrap-pincode-input.js"),
tags$script(src = "pincodeBinding.js")
),
br(),
pincodeInput("pincode", label = "Enter pincode"),
br(),
h3("You entered:"),
verbatimTextOutput("pincodeValue")
)
server <- function(input, output, session){
output[["pincodeValue"]] <- renderPrint({
input[["pincode"]]
})
}
shinyApp(ui, server)
Note that the pincode input only accepts digits, not alphabetical characters. I don't know whether this is what you want?
EDIT: clearable pincode input
Add this CSS file in the www folder, name it pincode-input.css:
.clearable {
padding: 1px 6px 1px 1px;
display: inline-flex;
}
.clearable span {
cursor: pointer;
color: blue;
font-weight: bold;
visibility: hidden;
margin-left: 5px;
}
Replace pincodeBinding.js with this file:
var pincodeBinding = new Shiny.InputBinding();
$.extend(pincodeBinding, {
find: function (scope) {
return $(scope).find(".pincode");
},
getValue: function (el) {
return $(el).val();
},
setValue: function(el, value) {
$(el).val(value);
},
subscribe: function (el, callback) {
$(el).on("change.pincodeBinding", function (e) {
callback();
});
},
unsubscribe: function (el) {
$(el).off(".pincodeBinding");
},
initialize: function(el) {
var $el = $(el);
var clearBtn = el.nextElementSibling;
$el.pincodeInput({
inputs: $el.data("ndigits"),
hidedigits: $el.data("hide"),
complete: function(value, e, errorElement){
Shiny.setInputValue($el.attr("id"), value);
},
change: function(){
clearBtn.style.visibility = ($el.val().length) ? "visible" : "hidden";
}
});
clearBtn.onclick = function() {
this.style.visibility = "hidden";
$el.pincodeInput().data("plugin_pincodeInput").clear();
Shiny.setInputValue($el.attr("id"), "");
};
}
});
Shiny.inputBindings.register(pincodeBinding);
The app:
library(shiny)
pincodeInput <- function(inputId, width = "30%", height = "100px",
label = NULL, ndigits = 4, hideDigits = FALSE){
tags$div(style = sprintf("width: %s; height: %s;", width, height),
shiny:::shinyInputLabel(inputId, label),
tags$span(
class = "clearable",
tags$input(id = inputId, class = "pincode", type = "text",
`data-ndigits` = ndigits,
`data-hide` = ifelse(hideDigits, "true", "false")
),
tags$span(title = "Clear", HTML("×"))
)
)
}
ui <- fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "bootstrap-pincode-input.css"),
tags$link(rel = "stylesheet", href = "pincode-input.css"),
tags$script(src = "bootstrap-pincode-input.js"),
tags$script(src = "pincodeBinding.js")
),
br(),
pincodeInput("pincode", label = "Enter pincode"),
br(),
h3("You entered:"),
verbatimTextOutput("pincodeValue")
)
server <- function(input, output, session){
output[["pincodeValue"]] <- renderPrint({
input[["pincode"]]
})
}
shinyApp(ui, server)

Is there any way to add custom R-function action to a button in DT?

I'm trying to add a custom button performing the action defined by R-function to my datatable. I've used the same list of options in my R code as in Javascript code in Datatables manual, but it doesn't work.
Here is a code from Datatables manual:
$(document).ready(function() {
$('#example').DataTable( {
dom: 'Bfrtip',
buttons: [
{
text: 'My button',
action: function ( e, dt, node, config ) {
alert( 'Button activated' );
}
}
]
} );
} );
And here is my code in R:
require(DT)
DT::datatable(iris,
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(
list(
text = 'test',
action = print('1')
)
)
)
)
Executing it I've received an error:
Error in if (extend != "collection") extend else listButtons(cfg) :
argument is of length zero
You have to set extend = "collection", like this:
library(DT)
datatable(iris,
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(
"copy",
list(
extend = "collection",
text = 'test',
action = DT::JS("function ( e, dt, node, config ) {
alert( 'Button activated' );
}")
)
)
)
)
But the action can only execute some Javascript, not a R command. However you can execute a R command by clicking a custom button if you put the datatable in a shiny application. Something like that:
library(shiny)
library(DT)
ui <- basicPage(
DTOutput("dtable")
)
server <- function(input, output, session){
output$dtable <- renderDT(
datatable(iris,
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons = list(
"copy",
list(
extend = "collection",
text = 'test',
action = DT::JS("function ( e, dt, node, config ) {
Shiny.setInputValue('test', true);
}")
)
)
)
)
)
observeEvent(input$test, {
if(input$test){
print("hello")
}
})
}
shinyApp(ui, server)

Resources