Skip to content

Commit

Permalink
add example on how to alter javascript --> R object
Browse files Browse the repository at this point in the history
  • Loading branch information
daattali committed Sep 17, 2016
1 parent bba05d9 commit 0a1250a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ This also seems like an appropriate place to mention that I am available for hir
- [Update multiple Shiny inputs without knowing input type](#update-input) ([code](./update-input))
- ["Busy..." / "Done!" / "Error" feedback after pressing a button](#busy-indicator) ([code](./busy-indicator))
- [Simple AJAX system for Shiny apps (JS -> R -> JS communication)](#api-ajax) ([code](./api-ajax))
- [Use a custom function to convert the JavaScript data into an R object](#javascript-to-r-handler)
- [Navigation in a Shiny app (forward/backwards in history)](#navigate-history) ([code](./navigate-history))
- [Sharing images on Facebook](#fb-share-img) ([code](./fb-share-img))
- [Facebook login through JavaScript in Shiny](#fb-login) ([code](./fb-login))
Expand Down Expand Up @@ -226,6 +227,12 @@ When the user clicks on a button, it usually results in some R code being run. S

Sometimes it's useful to be able to call an R function from JavaScript and use the return value from R back in JavaScript. This sort of communication is usually done with AJAX in JavaScript. This app shows how to implement a simple and ultra lightweight AJAX-like system in Shiny, to be able to call functions in R.

<h2 id="javascript-to-r-handler">Use a custom function to convert the JavaScript data into an R object</h2>

**[Link to code](./javascript-to-r-handler)**

When using `Shiny.onInputChange(name, data)` (as described [here](./message-javascript-to-r)), you are passing in a JavaScript object (`data`) and expect it to get converted to an R object (`input$name`). This conversion happens by serializing and deserializing the data to and from JSON. Usually `input$name` will look exactly like you'd expect it to, but it is possible for the conversion process to not do exactly what you want. Alternatively, you may just want to alter the data slightly in R before presenting it to Shiny.

<h2 id="navigate-history">Navigation in a Shiny app (forward/backwards in history)</h2>

**[Link to code](./navigate-history)**
Expand Down
17 changes: 17 additions & 0 deletions javascript-to-r-handler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Use a custom function to convert the JavaScript data into an R object

When using `Shiny.onInputChange(name, data)` (as described [here](../message-javascript-to-r)), you are passing in a JavaScript object (`data`) and expect it to get converted to an R object (`input$name`). This conversion happens by serializing and deserializing the data to and from JSON. Usually `input$name` will look exactly like you'd expect it to, but it is possible for the conversion process to not do exactly what you want. Alternatively, you may just want to alter the data slightly in R before presenting it to Shiny.

This is where the `shiny::registerInputHandler()` function comes in: it allows you to transform the data passed in from JavaScript before it gets used as `input$`. For example, suppose you use `Shiny.onInputChange("myobj", value)` to send a value from JavaScript to R, but you want `input$myobj` to be automatically converted into a list. There are two simple steps you'd need to follow:

1. In JavaScript, change `Shiny.onInputChange("myobj", value)` to `Shiny.onInputChange("myobj:mylist", value)`. Notice that we append `:<type>` to the name of the object. This specifices the type of object that is being passed to Shiny, so that Shiny will know what handler to call when deserialization its value.

2. In R, define the following function:

```
shiny::registerInputHandler("mylist", function(data, ...) {
list(data)
}, force = TRUE)
```

Now if you access `input$myobj` in shiny, the value will be wrapped in a list. Of course this particular example isn't terribly useful, but this principle can be applied in real apps (for example, you can see how I've used it in [`timevis`](https://github.com/daattali/timevis/blob/v0.2/R/utils.R#L2-L7)).
34 changes: 34 additions & 0 deletions javascript-to-r-handler/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
library(shiny)

jscode <- '
$(function() {
$(document).keypress(function(e) {
Shiny.onInputChange("keypress1", e.key);
Shiny.onInputChange("keypress2:mylist", e.key);
});
});
'

shiny::registerInputHandler("mylist", function(data, ...) {
list(data)
}, force = TRUE)

ui <- fluidPage(
tags$head(tags$script(HTML(jscode))),
h3("Press any key"),
"Raw key press:",
verbatimTextOutput("text1"),
"Key press wrapped in a list:",
verbatimTextOutput("text2")
)

server <- function(input, output, session) {
output$text1 <- renderPrint({
input$keypress1
})
output$text2 <- renderPrint({
input$keypress2
})
}

shinyApp(ui, server)

0 comments on commit 0a1250a

Please sign in to comment.