forked from daattali/advanced-shiny
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial commit: two versions of multiple scrollspy solutions and upda…
…te all inputs solution
- Loading branch information
0 parents
commit c0c59cd
Showing
16 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.Rproj.user | ||
.Rhistory | ||
.RData |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Version: 1.0 | ||
|
||
RestoreWorkspace: Default | ||
SaveWorkspace: Default | ||
AlwaysSaveHistory: Default | ||
|
||
EnableCodeIndexing: Yes | ||
UseSpacesForTab: Yes | ||
NumSpacesForTab: 2 | ||
Encoding: UTF-8 | ||
|
||
RnwWeave: Sweave | ||
LaTeX: pdfLaTeX |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Multiple scrollspy - advanced | ||
|
||
*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 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 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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
library(shiny) | ||
library(shinyjs) | ||
|
||
ui <- navbarPage( | ||
"Bootstrap scrollspy on multiple tabs", | ||
id = "navbar", | ||
header = div( | ||
useShinyjs(), | ||
extendShinyjs("www/app-shinyjs.js"), | ||
includeCSS("www/app.css"), | ||
includeScript("www/app.js"), | ||
includeScript("https://cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/1.4.3/jquery.scrollTo.min.js") | ||
), | ||
|
||
# tab 1 contains 4 sections and a scrollspy on the left with text | ||
tabPanel( | ||
"tab1", | ||
div(id = "tab1-content", | ||
fluidRow( | ||
column( | ||
4, | ||
div( | ||
id = "tab1-scrollspy", | ||
class = "potential-scrollspy", | ||
tags$ul( | ||
class = "nav nav-pills nav-stacked", | ||
tags$li(tags$a(href = "#section1-1", "Section 1-1")), | ||
tags$li(tags$a(href = "#section1-2", "Section 1-2")), | ||
tags$li(tags$a(href = "#section1-3", "Section 1-3")), | ||
tags$li(tags$a(href = "#section1-4", "Section 1-4")) | ||
) | ||
) | ||
), | ||
column( | ||
8, | ||
div(id = "section1-1", | ||
class = "scrollspy-section", | ||
p('Section 1-1') | ||
), | ||
div(id = "section1-2", | ||
class = "scrollspy-section", | ||
p('Section 1-2') | ||
), | ||
div(id = "section1-3", | ||
class = "scrollspy-section", | ||
p('Section 1-3') | ||
), | ||
div(id = "section1-4", | ||
class = "scrollspy-section", | ||
p('Section 1-4') | ||
) | ||
) | ||
) | ||
) | ||
), | ||
|
||
# tab 2 contains 3 sections and a scrollspy on the right without text | ||
tabPanel( | ||
"tab2", | ||
div(id = "tab2-content", | ||
fluidRow( | ||
column( | ||
8, | ||
div(id = "section2-1", | ||
class = "scrollspy-section", | ||
p('Section 2-1') | ||
), | ||
div(id = "section2-2", | ||
class = "scrollspy-section", | ||
p('Section 2-2') | ||
), | ||
div(id = "section2-3", | ||
class = "scrollspy-section", | ||
p('Section 2-3') | ||
) | ||
), | ||
column( | ||
4, | ||
div( | ||
id = "tab2-scrollspy", | ||
class = "potential-scrollspy", | ||
`data-offset` = 50, | ||
tags$ul( | ||
class = "nav nav-pills nav-stacked", | ||
tags$li(tags$a(href = "#section2-1")), | ||
tags$li(tags$a(href = "#section2-2")), | ||
tags$li(tags$a(href = "#section2-3")) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
|
||
server <- function(input, output, session) { | ||
# when changing tabs, update the scrollspy control | ||
observeEvent(input$navbar, { | ||
js$updateScrollspy(input$navbar) | ||
}) | ||
} | ||
|
||
shinyApp(ui = ui, server = server) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// update the active scrollspy control and refresh so that it will function | ||
shinyjs.updateScrollspy = function(tab) { | ||
// make all scrollspy controls inactive | ||
$('active-scrollspy').removeClass('active-scrollspy'); | ||
// get the content in the current tab | ||
var $tabContent = $('#' + tab + '-content'); | ||
if ($tabContent.length) { | ||
// find the scrollspy control in the current tab | ||
var $scrollspy = $tabContent.find('.potential-scrollspy'); | ||
if ($scrollspy.length) { | ||
// mark the scrollspy in the current tab as active | ||
$scrollspy.addClass('active-scrollspy'); | ||
// figure out the offset for this scrollspy | ||
var offset = 0; | ||
if ($scrollspy.data('offset')) { | ||
offset = $scrollspy.data('offset'); | ||
} | ||
// update the scrollspy object | ||
$('body').data('bs.scrollspy').options.offset = offset; | ||
$('body').scrollspy('refresh'); | ||
// unbind click events and re-bind clicks to animate scrolling | ||
$scrollspy.unbind('click.scrollto'); | ||
$scrollspy.bind('click.scrollto', 'ul li a', function(event) { | ||
event.preventDefault(); | ||
$.scrollTo(event.target.hash, 500, { | ||
offset: -offset | ||
}); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#tab1-content .scrollspy-section { | ||
height: 500px; | ||
border: 1px solid #DDD; | ||
} | ||
#tab1-scrollspy { | ||
position: fixed; | ||
} | ||
#tab1-scrollspy li > a { | ||
background-color: #FFF; | ||
} | ||
#tab1-scrollspy li > a:hover { | ||
background-color: #EEE; | ||
} | ||
#tab1-scrollspy li.active > a { | ||
background-color: #AAA; | ||
} | ||
#tab2-content .scrollspy-section { | ||
height: 900px; | ||
border: 1px solid #DDD; | ||
} | ||
#tab2-scrollspy { | ||
position: fixed; | ||
top: 300px; | ||
} | ||
#tab2-scrollspy li > a { | ||
padding: 0; | ||
width: 15px; | ||
height: 15px; | ||
background-color: #DDD; | ||
margin-bottom: 5px; | ||
} | ||
#tab2-scrollspy li > a:hover { | ||
background-color: #AAA; | ||
} | ||
#tab2-scrollspy li.active > a { | ||
background-color: #444; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// initialize common scrollspy control | ||
$(function() { | ||
$('body').scrollspy({ target: '.active-scrollspy' }) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Multiple scrollspy - basic | ||
|
||
*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. | ||
|
||
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
library(shiny) | ||
library(shinyjs) | ||
|
||
ui <- navbarPage( | ||
"Bootstrap scrollspy on multiple tabs", | ||
id = "navbar", | ||
|
||
header = div( | ||
useShinyjs(), | ||
extendShinyjs("www/app-shinyjs.js"), | ||
includeCSS("www/app.css"), | ||
includeScript("www/app.js"), | ||
|
||
# create a common scrollspy | ||
div( | ||
id = "myscrollspy", | ||
tags$ul( | ||
class = "nav nav-pills nav-stacked" | ||
) | ||
) | ||
), | ||
|
||
# tab 1 has 4 sections | ||
tabPanel( | ||
"tab1", | ||
div(id = "tab1-content", | ||
div(id = "section1-1", | ||
class = "scrollspy-section", | ||
p('Section 1-1') | ||
), | ||
div(id = "section1-2", | ||
class = "scrollspy-section", | ||
p('Section 1-2') | ||
), | ||
div(id = "section1-3", | ||
class = "scrollspy-section", | ||
p('Section 1-3') | ||
), | ||
div(id = "section1-4", | ||
class = "scrollspy-section", | ||
p('Section 1-4') | ||
) | ||
) | ||
), | ||
|
||
# tab 2 has 3 sections | ||
tabPanel( | ||
"tab2", | ||
div(id = "tab2-content", | ||
div(id = "section2-1", | ||
class = "scrollspy-section", | ||
p('Section 2-1') | ||
), | ||
div(id = "section2-2", | ||
class = "scrollspy-section", | ||
p('Section 2-2') | ||
), | ||
div(id = "section2-3", | ||
class = "scrollspy-section", | ||
p('Section 2-3') | ||
) | ||
) | ||
) | ||
) | ||
|
||
server <- function(input, output, session) { | ||
# when changing tabs, update the scrollspy control | ||
observeEvent(input$navbar, { | ||
js$updateScrollspy(input$navbar) | ||
}) | ||
} | ||
|
||
shinyApp(ui = ui, server = server) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// update scrollspy control with the contents of the current tab | ||
// and refresh the control to make the changes take effect | ||
shinyjs.updateScrollspy = function(tab) { | ||
if (tab == 'tab1' || tab == 'tab2') { | ||
var $tabContent = $('#' + tab + '-content'); | ||
var tabSections = $tabContent.find('.scrollspy-section'); | ||
var scrollspyHtml = ''; | ||
$.each(tabSections, function(idx, el) { | ||
scrollspyHtml += '<li><a href=\"#' + el.id + '\"></a></li>'; | ||
}); | ||
$('#myscrollspy').children('ul').html(scrollspyHtml); | ||
$('body').scrollspy('refresh'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#tab1-content div { | ||
height: 500px; | ||
border: 1px solid #DDD; | ||
} | ||
#tab2-content div { | ||
height: 900px; | ||
border: 1px solid #DDD; | ||
} | ||
#myscrollspy { | ||
position: fixed; | ||
top: 300px; | ||
left: 100px; | ||
} | ||
#myscrollspy li > a { | ||
padding: 0; | ||
width: 15px; | ||
height: 15px; | ||
background-color: #DDD; | ||
margin-bottom: 5px; | ||
} | ||
#myscrollspy li > a:hover { | ||
background-color: #AAA; | ||
} | ||
#myscrollspy li.active > a { | ||
background-color: #444; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// initialize common scrollspy control | ||
$(function() { | ||
$('body').scrollspy({ target: '#myscrollspy' }) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Update any Shiny input without knowing input type | ||
|
||
*Dean Attali, July 2015* | ||
|
||
Shiny allows you to update an input element only if you know the type of input it is. Furthermore, Shiny only allows you to update input elements one by one. This Shiny app demonstrates a solution to these two problems. | ||
|
||
First, the common Shiny input builder functions are wrapped by a custom function that mimics the Shiny function but also adds the input type information to the input's HTML. Then whenever you want to update an input only based on its ID, we can use JavaScript to determine the type of input, report it back to Shiny, and then call the correct update function. This is done with a call to `updateShinyInput(session, "inputid", "new value")`. You can also use `updateShinyInputs(list(...))` to update many inputs together in one call. | ||
|
||
Note that this solution assumes you're using the proper shiny functions to create inputs. More specifically, this won't work if creating input elements manually with HTML (for example, you should always call "textInput" rather than create a | ||
<input type='button'> HTML). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
library(shiny) | ||
library(shinyjs) | ||
|
||
source("update-input.R") | ||
|
||
ui <- fluidPage( | ||
useShinyjs(), | ||
extendShinyjs("www/app-shinyjs.js"), | ||
|
||
textInput("text", "Text input", "some text"), | ||
selectInput("select", "Select input", LETTERS), | ||
numericInput("numeric", "Numeric input", 5), | ||
actionButton("btn", "Reset text to 'new value', select to 'G', and number to '9'", class = "btn-primary") | ||
) | ||
|
||
server <- function(input, output, session) { | ||
observeEvent(input$btn, { | ||
newValues <- list("text" = "new value", | ||
"select" = "G", | ||
"numeric" = 9) | ||
updateShinyInputs(session, newValues) | ||
# OR one by one | ||
# updateShinyInput(session, "text", "new value") | ||
}) | ||
} | ||
|
||
shinyApp(ui = ui, server = server) |
Oops, something went wrong.