Skip to content

Commit

Permalink
some updates
Browse files Browse the repository at this point in the history
  • Loading branch information
daattali committed May 8, 2016
1 parent 0aa6565 commit 98d2615
Show file tree
Hide file tree
Showing 31 changed files with 274 additions and 301 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
R shiny tricks (shinyjs - reset inputs, disable textinput when radio button is selected, loading..., state variables to use in ui - can be useful if want to use conditionalPanel with a variable that's calcualted in the server, global.R, splitting off big ui/server into files, shiny debugging such as add a `options(warn=2)` at top of UI and server if getting a "ERRORR: canot open the conenction" butyou have no clue where the error's happening or what file it's failing at, ajax loading on image, ajax loading + error on submit button), how to do toggle button (conditionalPanel with condition being input % 2 == 1)
R shiny tricks (shinyjs - reset inputs, disable textinput when radio button is selected, loading..., state variables to use in ui - can be useful if want to use conditionalPanel with a variable that's calcualted in the server, global.R, splitting off big ui/server into files, shiny debugging such as add a `options(warn=2)` at top of UI and server if getting a "ERRORR: canot open the conenction" butyou have no clue where the error's happening or what file it's failing at, how to do toggle button (conditionalPanel with condition being input % 2 == 1)

withBusyIndicator

Expand Down
6 changes: 3 additions & 3 deletions api-ajax/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Sometimes it's useful to be able to call an R function from JavaScript and use t
Using this system is easy:
1. Include `api.js` in your Shiny app's UI
2. Include `api.R` in your Shiny app's server
3. Define the functions in R that you want to be able to call from JavaScript. Each function name must begin with `api.` and takes a single argument which is a list of the given parameters passed from JavaScript. This function should return a list (can be an empty list), which will be passed to the callback function in JavaScript if a callback was provided.
4. In JavaScript, make a call to `api.call(params)`, where `params` is an object that contains all the parameters as key-value pairs. You must specify the `_method` parameter -- this is the R function that will get called. For example, if in R you defined a function `api.myfunc` then you can call it in JavaScript with `api.call('_method' : 'myfunc')` (notice that the prefix `api.` is ommitted). You can optionally provide `_callback` and `_failureCallback` functions which can be called when the R function completes or when it throws an error. You can also add any other arbitrary parameters, and they will be available to you in the R function.
3. In your R code: define the functions that you want to be able to call from JavaScript. Each function must have a name beginning with `api.` and take a single argument which is a list of the parameters passed from JavaScript. This function should return a list (can be an empty list), which will be passed to the callback function in JavaScript (if a callback was provided).
4. In your JavaScript code: make a call to `api.call(params)`, where `params` is an object that contains all the parameters as key-value pairs. You must specify the `_method` parameter -- this is the R function that will get called. For example, if in R you defined a function `api.myfunc` then you can call it in JavaScript with `api.call('_method' : 'myfunc')` (notice that the prefix `api.` is ommitted). You can optionally provide `_callback` and `_failureCallback` functions which can be called when the R function completes or when it throws an error. You can also add any other arbitrary parameters, and they will be available to you in the R function.

Take a look at the source code of the sample app to see this in action.
This may sound a bit complicated, but if you take a look at the source code of the sample app you'll see it's actually pretty simple to use.
8 changes: 3 additions & 5 deletions api-ajax/app.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Dean Attali, July 2015

library(shiny)
library(shinyjs)

ui <- fluidPage(
tags$head(
includeScript("www/api.js"),
includeScript("www/app.js")
includeScript("www/api.js"), # Always include this file
includeScript("www/app.js") # JavaScript specific to this app
),
actionButton("getRversion", "R version API call"),
actionButton("errorFunction", "API call with error")
Expand All @@ -18,7 +17,6 @@ server <- function(input, output, session) {
source("api.R", local = TRUE)$value

api.getRversion <- function(params) {
# do some stuff
# don't forget you have access to all the parameters sent by javascript
# inside the "params" variable

Expand All @@ -33,7 +31,7 @@ server <- function(input, output, session) {
api.errorExample <- function(params) {
# this function will throw an error to show what happens on the javsacript
# side when an error occurs
stop("some error happened")
stop("sample error message")
}
}

Expand Down
4 changes: 3 additions & 1 deletion fb-login/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

*Dean Attali, July 2015*

This app shows how you can use the AJAX-like system in Shiny to authorize a user using Facebook's JavaScript library and pass the user's information to R for processing. Because of Facebook's app settings, in order for the app to work properly locally, you need to replace `127.0.0.1` with `fuf.me`.
This app shows how you can use the AJAX-like system in Shiny to authorize a user using Facebook's JavaScript library and pass the user's information to R for processing. Because of Facebook's app settings, in order for the app to work properly locally, you need to replace `127.0.0.1` in the URL with `fuf.me` (testing FB apps locally is a big pain and is out of the scope of this example, you might have to do lots of Googling and StackOverflow-ing to get it right).

Note that this example uses the [AJAX system](../api-ajax) shown in another example.
1 change: 0 additions & 1 deletion fb-login/app.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Dean Attali, July 2015

library(shiny)
library(shinyjs)

ui <- fluidPage(
tags$head(
Expand Down
7 changes: 7 additions & 0 deletions fb-share-img/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Sharing images on Facebook

*Dean Attali, July 2015*

There are two Facebook share buttons: the first one (easier) uses the conventional way of sharing an image on Facebook using an image URL and will ask the user to confirm sharing. The second method shares a base64 encoded image (which means we get get the image data straight from Shiny) and can be done completely programatically, but it's a little bit more hacky.

A user will be asked to log in to Facebook if they aren't logged in. Note that the Facebook app settings do not allow a URL of `localhost` or `127.0.0.1` to be used, so in order to run this app locally you will need to change the URL to `fuf.me`.
23 changes: 23 additions & 0 deletions fb-share-img/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Dean Attali, July 2015

library(shiny)

ui <- fluidPage(
tags$head(
includeScript("www/app.js")
),
h3("In order for Facebook sharing to work, you need to change the URL from 127.0.0.1 to 'fuf.me'"),
actionButton("fbShareBtn", "Share image with popup (URL)"), br(), br(),
actionButton("fbShare64Btn", "Share image programatically (base-64, generated in Shiny)"),
plotOutput("plot")
)

server <- function(input, output, session) {
# generate a random plot each time with timestamp, just to have a unique plot each time
output$plot <- renderPlot({
num <- as.integer(sample(5:100, 1))
plot(1:num, main = paste(num, Sys.time()))
})
}

shinyApp(ui = ui, server = server)
25 changes: 0 additions & 25 deletions share-image-social-media/www/app.js → fb-share-img/www/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,37 +53,12 @@ app = function() {
});
};

// register click event on linkedin share button
$("#linkedinShareBtn").click(function() {
IN.User.authorize(app.linkedinShare);
});

// register click event on facebook share button
$('#fbShareBtn').click(app.facebookShare);

// register click event on facebook share base64 image button
$('#fbShare64Btn').click(app.facebookShare64Click);
},

// share image on linkedin
linkedinShare : function() {
var params = {
"content": {
"title" : payload.title,
"description" : payload.description,
"submitted-image-url" : payload.picture,
"submitted-url" : payload.link
},
"visibility": {
"code": "anyone"
}
};
IN.API.Raw("/people/~/shares?format=json")
.method("POST")
.body(JSON.stringify(params))
.result(function(o){ alert("LinkedIn share success!"); console.log(o); })
.error(function(o){ alert("LinkedIn shard error"); console.log(o); });
},

// share image on facebook
facebookShare : function() {
Expand Down
4 changes: 3 additions & 1 deletion hide-tab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

*Dean Attali, July 2015*

This app demonstrates how `shinyjs` can be used to hide/show a specific tab in a `tabsetPanel`. In order to use this trick, the `tabsetPanel` must have an id. Using this id and the value of the specific tab you want to hide/show, you can call `shinyjs::hide()`/`shinyjs::show()`/`shinyjs::toggle()`.
This app demonstrates how `shinyjs` can be used to hide/show a specific tab in a `tabsetPanel`. In order to use this trick, the `tabsetPanel` must have an id. Using this id and the value of the specific tab you want to hide/show, you can call `shinyjs::hide()`/`shinyjs::show()`/`shinyjs::toggle()`.

This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to show/hide the tab.
2 changes: 1 addition & 1 deletion loading-screen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

This simple app shows how to add a "Loading..." screen overlaying the main app while the app's server is initializing. The main idea is to include an overlay element that covers the entire app (using CSS), hide the main app's UI, and at the end of the server function show the UI and hide the overlay.

Note that this will only show the Loading screen while the server is initializing, but it will not show up until the app's UI is finished rendering.
This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to show/hide elements.
52 changes: 26 additions & 26 deletions loading-screen/app.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,32 @@ appCSS <- "
}
"

shinyApp(
ui = fluidPage(
useShinyjs(),
inlineCSS(appCSS),
# Loading message
div(
id = "loading-content",
h2("Loading...")
),
# The main app code goes here
ui <- fluidPage(
useShinyjs(),
inlineCSS(appCSS),

# Loading message
div(
id = "loading-content",
h2("Loading...")
),

# The main app code goes here
hidden(
div(
id = "app-content",
p("This is a simple example of a Shiny app with a loading screen."),
p("You can view the source code",
a(href = "https://github.com/daattali/shiny-server/blob/master/loading-screen",
"on GitHub")
)
p("This is a simple example of a Shiny app with a loading screen.")
)
),
server = function(input, output) {
# Simulate work being done for 1 second
Sys.sleep(1)

# Hide the loading message when the rest of the server function has executed
hide(id = "loading-content", anim = TRUE, animType = "fade")
}
)
)
)

server <- function(input, output) {
# Simulate work being done for 1 second
Sys.sleep(1)

# Hide the loading message when the rest of the server function has executed
hide(id = "loading-content", anim = TRUE, animType = "fade")
show("app-content")
}

shinyApp(ui, server)
4 changes: 3 additions & 1 deletion multiple-pages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

*Dean Attali, July 2015*

This app demonstrates how to write a Shiny app that has a sequence of different pages, where the user can navigate to the next/previous page. This can be useful in many scenarios that involve a multi-step process. This behaviour can also be achieved by simply using tabs, but when using tabs the user can freely move from any tab to any other tab, while this approach restricts the user to only move to the previous/next step, and can also control when the user can move on to the next page.
This app demonstrates how to write a Shiny app that has a sequence of different pages, where the user can navigate to the next/previous page. This can be useful in many scenarios that involve a multi-step process. This behaviour can also be achieved by simply using tabs, but when using tabs the user can freely move from any tab to any other tab, while this approach restricts the user to only move to the previous/next step, and can also control when the user can move on to the next page (by enabling/disabling the navigation buttons using `shinyjs::enable` and `shinyjs::disable`).

This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to show/hide the pages and to enable/disable the buttons.
65 changes: 33 additions & 32 deletions multiple-pages/app.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,38 @@ library(shinyjs)

NUM_PAGES <- 5

shinyApp(
ui = fluidPage(
useShinyjs(),
hidden(
lapply(seq(NUM_PAGES), function(i) {
div(
class = "page",
id = paste0("step", i),
"Step", i
)
})
),
br(),
actionButton("prevBtn", "< Previous"),
actionButton("nextBtn", "Next >")
),
server = function(input, output, session) {
rv <- reactiveValues(page = 1)

observe({
toggleState(id = "prevBtn", condition = rv$page > 1)
toggleState(id = "nextBtn", condition = rv$page < NUM_PAGES)
hide(selector = ".page")
show(sprintf("step%s", rv$page))
ui <- fluidPage(
useShinyjs(),
hidden(
lapply(seq(NUM_PAGES), function(i) {
div(
class = "page",
id = paste0("step", i),
"Step", i
)
})

navPage <- function(direction) {
rv$page <- rv$page + direction
}

observeEvent(input$prevBtn, navPage(-1))
observeEvent(input$nextBtn, navPage(1))
}
),
br(),
actionButton("prevBtn", "< Previous"),
actionButton("nextBtn", "Next >")
)

server <- function(input, output, session) {
rv <- reactiveValues(page = 1)

observe({
toggleState(id = "prevBtn", condition = rv$page > 1)
toggleState(id = "nextBtn", condition = rv$page < NUM_PAGES)
hide(selector = ".page")
show(sprintf("step%s", rv$page))
})

navPage <- function(direction) {
rv$page <- rv$page + direction
}

observeEvent(input$prevBtn, navPage(-1))
observeEvent(input$nextBtn, navPage(1))
}

shinyApp(ui, server)
8 changes: 5 additions & 3 deletions multiple-scrollspy-advanced/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
*Dean Attali, July 2015*

The Bootstrap scrollspy plugin does not support multiple scrollspy objects per page.
This Shiny app demonstrates how to support scrollspy on multiple tabs by allowing each tab to have its own independent scrollspy control and using JavaScript to ensure only the scrollspy on the current tab is activated.
This Shiny app demonstrates how to support scrollspy on multiple tabs by allowing each tab to have its own independent scrollspy control and using JavaScript to ensure only the scrollspy on the current tab is activated. Look at the code to see how this is achieved.

This approach is very flexible and great to use when you want to define custom scrollspy controls on each tab. Initially I thought it'd be easy to simply "destory" a scrollspy control and initialize a different one, but it seems like destorying scrollspy objects is not possible in Bootstrap 3 (although it sounds like in Bootstrap 4 it will be supported), so a more clever trick has to be used to be able to "reset" the active scrollspy control.
This approach is very flexible and great to use when you want to define custom scrollspy controls on each tab. Initially I thought it'd be easy to simply "destroy" a scrollspy control and initialize a different one, but it seems like destorying scrollspy objects is not possible in Bootstrap 3 (although it sounds like in Bootstrap 4 it will be supported), so a more clever trick has to be used in order to "reset" the active scrollspy control.

This method also supports having a different offset for the scrollspy on each tab by adding a `data-offset` attribute to the scrollspy HTML tag. This method also uses the jQuery scrollTo plugin to animate the scrolling for a better UX.
This method also supports having a different offset for the scrollspy on each tab by adding a `data-offset` attribute to the scrollspy HTML tag. This method also uses the jQuery scrollTo plugin to animate the scrolling for a better UX.

This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to call custom JavaScript functions.
6 changes: 4 additions & 2 deletions multiple-scrollspy-basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

*Dean Attali, July 2015*

The Bootstrap scrollspy plugin does not support multiple scrollspy objects per page. This Shiny app demonstrates how to support scrollspy on multiple tabs by having one common scrollspy control that gets updated via JavaScript whenever a tab is changed to reflect the contents of the new tab.
The Bootstrap scrollspy plugin does not support multiple scrollspy objects per page. This Shiny app demonstrates how to support scrollspy on multiple tabs by having one common scrollspy control that gets updated via JavaScript whenever a tab is changed to reflect the contents of the new tab. Look at the code to see how this is achieved.

This approach is useful if you don't want to have to hardcode the scrollspy code since it will automatically generate the scrollspy control for each tab. However, the major disadvantage of this approach is that if you want different pages to have very different looking scrollspy controls, it will be hard to achieve with this method because only one common control is created.
This approach is useful if you don't want to have to hardcode the scrollspy code since it will automatically generate the scrollspy control for each tab. However, the major disadvantage of this approach is that if you want different pages to have very different looking scrollspy controls, it will be hard to achieve with this method because only one common control is created.

This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to call custom JavaScript functions.
6 changes: 5 additions & 1 deletion navigate-history/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ For example, try this sequence of events to see what this app can do:
- click the "back" button in your browser navigation
- copy the URL
- click the "next" button in your browser navigation
- in a different window, go to the URL that you copied earlier (it will automatically navigate to the search page and show the search term)
- in a different window, go to the URL that you copied earlier (it will automatically navigate to the search page and show the search term)

The code is a bit complex and might take some time to understand how it works. This is certainly not an ideal solution, I'd love to know if someone has a nicer method for navigating a Shiny app. It's possible that the core Shiny team will work on this and that soon this functionality will be native to shiny.

This example makes use of the [shinyjs](https://github.com/daattali/shinyjs) package to call custom JavaScript functions.
6 changes: 4 additions & 2 deletions plot-spinner/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Show a spinning "loading" animation while plot is recalculating
# Show a spinning "loading" animation while a plot is recalculating

*Dean Attali, July 2015*

When a Shiny plot is recalculating, the plot gets grayed out. This app shows how you can add a spinner wheel on top of the plot while it is recalculating, to make it clear to the user that the plot is reloading. There can be many different ways to achieve a similar result using different combinations of HTML/CSS, this is just the simplest one I came up with.
When a Shiny plot is recalculating, the plot gets grayed out. This app shows how you can add a spinner wheel on top of the plot while it is recalculating, to make it clear to the user that the plot is reloading. There can be many different ways to achieve a similar result using different combinations of HTML/CSS, this is just the simplest one I came up with.

The idea is to place a spinner image in the same container as the plot, center it, and give it a below-default z-index. Whenever the plot is recalculting, make the plot's z-index even lower so that the spinner will show.
Loading

0 comments on commit 98d2615

Please sign in to comment.