How to disable tabpanel in the app deployed on shinyapps.io? - tabs

I have a problem disabling tabpanel in my shiny app. To do so, I tried the following code:
library(shiny)
library(shinyjs)
ui <- navbarPage("Hello",
tabPanel("Panel1",
useShinyjs()),
tabPanel("Panel2"),
tabPanel("Panel3")
)
server <- function(input, output, session) {
disable(selector = '.navbar-nav a[data-value="Panel2"]')
disable(selector = '.navbar-nav a[data-value="Panel3"]')
}
shinyApp(ui, server)
Everything is working fine, until I deploy the app on shinyapps.io. Then weird things happen - clicking on a tab refreshes the whole app or disabling does not work at all and the app lets me access the panel I want to block. You can see this behavior here
https://krystynagrzesiak.shinyapps.io/test_panel/
where I deployed the code I posted above.
I'm not very familiar with shinyjs. I tried to inspect the elements of panel in my browser and everything seems to be fine, all the ones I want to block contain class="disabled". I checked that on Firefox and Chrome and there is no difference.
I'm running out of ideas. Is there something I'm doing wrong? Is there any way of fixing it? Are there any other approaches that would work as I expect?
I would be very grateful for any help!

I have modified your example. I don't think you need to disable specific tabPanels by useShinyjs function disable. You could simply specify selectors in a separate css file, and set their property pointer-events to none.
# style.css
.navbar-nav a[data-value="Panel2"] {
pointer-events: none;
}
.navbar-nav a[data-value="Panel3"] {
pointer-events: none;
}
and R file
# app.R
library(shiny)
library(shinyjs)
ui <- navbarPage("Hello",
includeCSS("./www/style.css"),
tabPanel("Panel1"),
tabPanel("Panel2"),
tabPanel("Panel3")
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Hopefully it will solve your problem.

Related

Add external hyperlink to tabPanel or navbarMenu in r Shiny

I am trying to add external hyperlinks to the tabPabel and navbarMenu tabs/dropdowns in a navbarPage setup in Shiny (using bootstrapPage). I found multiple questions that refer to linking to another tab within a Shiny app, but I want to specifically link to another webpage without opening a new browser window.
I found the following questions that kind of get there:
How to direct to another web page after clicking tabPanel in Shiny App
Open URL by tabPanel in Shiny
The second question is what I want to do; however, when I use the following method to accomplish this, it adds a "phantom" tab:
tabPanel(a("Open Sales Gsheet", href="http://google.com", target="_blank"))
Here is some example code for the Shiny app setup that I am working with:
library(shiny); library(shinythemes)
ui <- bootstrapPage("",
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
tabPanel(title = HTML("Panel_1</a></li><li><a href='http://google.com' target='_blank'>test")), ## tabPanel hyperlink test (adds "phantom" tab)
navbarMenu(title = "Test Menu",
tabPanel(title = a("Open Sales Gsheet", href="http://google.com", target="_blank")) ## navbarMenu hyperlink test (adds "phantom" option)
)
)
)
server <- function(input, output, session) {
## empty server
}
shinyApp(ui, server)
Here is a screenshot of the "phantom" tab issue:
https://i.imgur.com/tIYbhzT.png
As you can see, both the tabPanel and navbarMenu tabs/dropdowns have additional "phantom" tabs that have been added as a result. The first question I posted above shows an answer that involves editing the html code (or the list that is produced in R)... but I cannot figure out how to do this with a tabPanel or navbarMenu object.
I just want this to look like a normal navbarPage dropdown where the tabPanel and navbarMenu selections link to an external site (in the same browser window - browseURL as an observeEvent in the server script does not work since it opens in another window). Any help would be appreciated!
It's tricky to add custom elements in a shiny navbar page but it can be done with some javascript. The following code should add your link to the dropdown menu in the navbar. Save it as a .js file in your app's base directory then include the script in your ui function.
navAppend.js in your app's base directory:
$(document).ready(function() {
$(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li>Open Sales Gsheet</li>');
});
in your ui:
ui <- tagList(
tags$head(includeScript("navAppend.js")),
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
# nav menu the link will be added to
navbarMenu(title = "Test Menu")
)
)

[Shiny]: Add link to another tabPanel in another tabPanel

I'm trying to put a link on my "home" tabPanel to all others tabPanels of my app.
The idea is as follows:
ui = navbarPage("",
tabPanel("home",
fluidPage(
fluidRow(box("this 1st box should lead me to tab1a")),
fluidRow(box("this 2nd box should lead me to tab1b")),
fluidRow(box("this 2nd box should lead me to tab2")))
),
navbarMenu("tab1",
tabPanel("tab1a"),
tabPanel("tab1b")),
tabPanel("tab2")
)
shinyApp(ui, server=function(input, output) {})
I've seen the answer in Add link panel tabs in Shiny with various top level navigation bars, but I couldn't implement it on my code, since it deals with html (which i've never worked before, so I'm not familiar with the functions etc) and the code considers tabPanels within the same tab (not sure if that's why it didn't work here, if maybe it didn't work because the tabs I'm trying to link are on a navbarPage or something).
Can anyone help me or tell me where i could learn how to implement this on my example?
This answer is purely JavaScripted, but very minimal, I guess. Since Shiny creates tabs with random number Ids, and does not give access to the Ids it used, this has do be done client-sided. But there is no knowledge of JavaScript needed to implement this to other scenarios. The JavaScript part is just for Copy/Paste and the trigger command is easy to understand.
What did I do? I installed a function, that finds the Navbar link corresponding to the desired tab, and just clicks it. This utility can be added to any element with the "onclick" attribute. There are no special tags (e.g. no "a" tag) required.
The code below should make it easy to customize this solution to fit your needs.
Note: I used the original Code with the box, although it does not have any visual effect.
Code:
library(shiny)
library(shinydashboard)
ui = shinyUI(
navbarPage("Header",
tabPanel("home",
tags$head(tags$script(HTML('
var fakeClick = function(tabName) {
var dropdownList = document.getElementsByTagName("a");
for (var i = 0; i < dropdownList.length; i++) {
var link = dropdownList[i];
if(link.getAttribute("data-value") == tabName) {
link.click();
};
}
};
'))),
fluidPage(
fluidRow(box("this 1st box should lead me to tab1a", onclick = "fakeClick('tab1a')")),
fluidRow(box("this 2nd box should lead me to tab1b", onclick = "fakeClick('tab1b')")),
fluidRow(box("this 2nd box should lead me to tab2", onclick = "fakeClick('tab2')"))
)
),
navbarMenu("tab1",
tabPanel("tab1a", "Some Text inside Tab 1a."),
tabPanel("tab1b", "Some Text inside Tab 1b.")
),
tabPanel("tab2", "Some Text inside Tab 2.")
)
)
server = function(input, output, session){}
runApp(shinyApp(ui, server), launch.browser = TRUE)
Have fun!

Custom html with download data button in Shiny

I'm wondering how to make the Shiny downloadHandler work with a custom html UI.
In my index.html I have the following:
<a id="downloadproject" class="shiny-download-link shiny-bound-output">export</a>
And in the server.R I have:
output$downloadproject <- downloadHandler(
filename = "test.csv",
content = function(file) {
test_data <- c(1,2,3,4,5,6,7)
write.csv(test_data, file)
}
)
However, I can't get it working. I've noticed inspecting the source on the demo page: http://shiny.rstudio.com/gallery/file-download.html that the link there points to a resource:
<a id="downloadData" class="btn shiny-download-link shiny-bound-output" href="session/58c63083742fd00d75ac37732eb224bc/download/downloadData?w=299e8cd2e7b56a2507a31ddbe72446fd2ce5d51f5940ea0a" target="_blank">
<i class="fa fa-download"></i>
Download
</a>
However, I guess that this it to be set by the downloadHandler from the server side. My a-tag in however does not get any href at all. Is what I'm looking to do even possible? Am I'm making some mistake here? Any ideas on how to fix this would be much appreciated.
I think the A tag is being modified by some javascript. If you just download the HTML source for that (which is in an iframe wrapper) then you don't see the long href.
So I further think your custom HTML UI doesn't include the right javascript that adjusts the tag.
I think its done by downloadLinkOutputBinding in shiny.js, line 1402 or thereabouts.
Those demos load a lot of js and css, some of it is clearly crucial!
I've just pasted your html and server.R into a test environment and it works - are you still having this problem?
In particular, it turns out that you can leave out the anchor's href tag (according to this post on the shiny forum).
Also, you only need class="shiny-download-link on the button (ie. no need for shiny-bound-output).
In most cases you will want to pass the downloadable data from the client to the server, so I'll mention how to do that too (thanks to this post). On the server:
output$downloadproject <- downloadHandler(
filename = function() { 'test.csv' },
content = function(file) {
write.csv(input$mydata, file)
}
)
And add some javascript into the html:
Shiny.onInputChange("mydata", [1,2,3,4,5,6,7]);
Hope that helps.

Strange IE11 form fields bug after selecting from dropdown

I'm experiencing a major bug in IE 11 (latest version 11.0.9600.16521 on Windows 7). When on any form if I open a select dropdown all the other form fields on the page freeze. I can 'unfreeze' them by adjusting the Window size (causing a redraw). This seems to happen on any form what-so-ever.
To reproduce:
Open IE 11.0.9600.16521
Go to http://www.wikipedia.org/
Select any language from the language dropdown
Result:
language dropdown does not appear to get updated on the screen
the search box appears to be frozen - i.e. focus on select box and start typing but no text appears. However if you adjust the window size the form fields are updated and go back to working as normal (until you interact with another select element)
I can't find much in Google for this issue so maybe it's just something specific to my settings. Only thing that sounds somewhat similar to what I'm experiencing is this: http://connect.microsoft.com/IE/feedback/details/806679/ie-11-desktop-selecting-an-item-from-a-drop-down-list-on-a-webpage-causes-the-tab-to-crash. Anyone else able to reproduce this?
I had a similar issue with IE11 that turned out to be any modification to the .text property of an SELECT-option element. I eventually found the "hint" on stackoverflow here
How to fix IE select issue when dynamically changing options.
In my case I use straight JavaScript, and with so many inter-dependent SELECT boxes had to come up with a generic solution, so my solution was to intercept (defineGetter) assignment to any .text property of an HTMLOptionElement, and set a 1 ms timer to perform an add element and remove element as in the referenced post that is titled "I have the fix. We have to add and remove options list to trigger the rendering in IE8." Notice the reference to IE8, AFAIK IE has had several issues with SELECT boxes since at least IE7, possibly earlier.
So the code I added to one of my global scripts is as follows:
try { var IE11; // IE10 and IE11 removed ActiveXObject from the window object but it can still be instantiated
IE11 = new ActiveXObject('MSXML2.DOMDocument.6.0');
IE11 = null;
if (typeof(HTMLOptionElement) != "undefined") {
try { HTMLOptionElement.prototype.__defineSetter__(
'text',
function(original) {
return function(newValue) { var sel;
original.call(this, newValue);
if (!(sel=this.parentElement).fixIE) sel.fixIE = window.setTimeout(_fixIE_(sel), 1);
}
}(HTMLOptionElement.prototype.__lookupSetter__('text')));
} catch(e) {};
}
} catch(e) {}
}
// IE11 broke SELECT boxes again, modifying any options .text attribute "freezes" the SELECT so it appears disabled
function _fixIE_(selBox) {
return _fixIE_;
function _fixIE_(){ var lc = selBox.options.length;
selBox.options.add(new Option('',''));
selBox.options.remove(lc);
selBox.fixIE = undefined;
}
}
Phil
Go to programs
Then widdcom folder
Right click bttray
Go compatibility
Tick run as admin
Restart
I had the same problem in IE 11 on Dell Windows 7.
It was solved by turning off hardware rendering in IE, as you suggested in your link.

SSRS 2008 R2 - SSRS 2012 - ReportViewer: Reports are blank in Safari and Chrome

I migrated our reporting services from version 2008 to another server version 2008 R2. In version 2008 the reports work fine on Safari. The new version 2008 R2 the reports do not show up at all. All I see is the parameter section and then the report is blank. Same in Chrome. According to Microsoft Safari IS supported if in a limited fashion. The reports are not complex. In fact I created a report that only had a line on it to see if it would show up in Safari but no, that report is completely blank as well. Did anyone make SSRS reports viewable on Safari? Do I have to mess with some kind of a configuration setting?
Ultimate solution (works in SSRS 2012 too!)
Append the following script to the following file (on the SSRS Server)
C:\Program Files\Microsoft SQL Server\MSRS10_50.MSSQLSERVER\Reporting Services\ReportManager\js\ReportingServices.js
function pageLoad() {
var element = document.getElementById("ctl31_ctl10");
if (element)
{
element.style.overflow = "visible";
}
}
Note: As azzlak noted, the div's name isn't always ctl31_ctl10. For SQL 2012 tryctl32_ctl09 and for 2008 R2 try ctl31_ctl09. If this solution doesn't work, look at the HTML from your browser to see if the script has worked properly changing the overflow:auto property to overflow:visible.
Solution for ReportViewer control
Insert into .aspx page (or into a linked .css file, if available) this style line
#reportViewer_ctl09 {
overflow:visible !important;
}
Reason
Chrome and Safari render overflow:auto in different way respect to IE.
SSRS HTML is QuirksMode HTML and depends on IE 5.5 bugs. Non-IE browsers don't have the IE quirksmode and therefore render the HTML correctly
The HTML page produced by SSRS 2008 R2 reports contain a div which has overflow:auto style, and it turns report into an invisible report.
<div id="ctl31_ctl10" style="height:100%;width:100%;overflow:auto;position:relative;">
I can see reports on Chrome by manually changing overflow:auto to overflow:visible in the produced webpage using Chrome's Dev Tools (F12).
I love Tim's solution, it's easy and working.
But there is still a problem: any time the user change parameters (my reports use parameters!) AJAX refreshes the div, the overflow:auto tag is rewritten, and no script changes it.
This technote detail explains what is the problem:
This happens because in a page built with AJAX panels, only the AJAX panels change their state, without refreshing the whole page. Consequently, the OnLoad events you applied on the <body> tag are only fired once: the first time your page loads. After that, changing any of the AJAX panels will not trigger these events anymore.
User einarq suggested this solution:
Another option is to rename your function to pageLoad. Any functions with this name will be called automatically by asp.net ajax if it exists on the page, also after each partial update. If you do this you can also remove the onload attribute from the body tag
So wrote the improved script that is shown in the solution.
Just include SizeToReportContent="true" as shown below
<rsweb:ReportViewer ID="ReportViewer1" runat="server" SizeToReportContent="True"...
I am using Chrome version 21 with SQL 2008 R2 SP1 and none of the above fixes worked for me. Below is the code that did work, as with the other answers I added this bit of code to Append to "C:\Program Files\Microsoft SQL Server\MSRS10_50.MSSQLSERVER\Reporting Services\ReportManager\js\ReportingServices.js" (on the SSRS Server) :
//Fix to allow Chrome to display SSRS Reports
function pageLoad() {
var element = document.getElementById("ctl31_ctl09");
if (element)
{
element.style.overflow = "visible";
}
}
This is a known issue. The problem is that a div tag has the style "overflow: auto" which apparently is not implemented well with WebKit which is used by Safari and Chrome (see Emanuele Greco's answer). I did not know how to take advantage of Emanuele's suggestion to use the RS:ReportViewerHost element, but I solved it using JavaScript.
Problem
Solution
Since "overflow: auto" is specified in the style attribute of the div element with id "ctl31_ctl10", we can't override it in a stylesheet file so I resorted to JavaScript. I appended the following code to "C:\Program Files\Microsoft SQL Server\MSRS10_50.MSSQLSERVER\Reporting Services\ReportManager\js\ReportingServices.js"
function FixSafari()
{
var element = document.getElementById("ctl31_ctl10");
if (element)
{
element.style.overflow = "visible"; //default overflow value
}
}
// Code from http://stackoverflow.com/questions/9434/how-do-i-add-an-additional-window-onload-event-in-javascript
if (window.addEventListener) // W3C standard
{
window.addEventListener('load', FixSafari, false); // NB **not** 'onload'
}
else if (window.attachEvent) // Microsoft
{
window.attachEvent('onload', FixSafari);
}
Note
There appears to be a solution for SSRS 2005 that I have not tried but I don't think it is applicable to SSRS 2008 because I can't find the "DocMapAndReportFrame" class.
My solution based on the ideas above.
function pageLoad() {
var element = document.querySelector('table[id*=_fixedTable] > tbody > tr:last-child > td:last-child > div');
if (element) {
element.style.overflow = "visible";
}
}
It's not limited to a certain id plus you don't need to include any other library such as jQuery.
Here is the solution I used for Report Server 2008 R2
It should work regardless of what the Report Server will output for use for in its "id" attribute of the table. I don't think you can always assume it will be "ctl31_fixedTable"
I used a mix of the suggestion above and some ways to dynamically load jquery libraries into a page from javascript file found here
On the server go to the directory:
C:\Program Files\Microsoft SQL Server\MSRS10_50.MSSQLSERVER\Reporting Services\ReportManager\js
Copy the jquery library jquery-1.6.2.min.js into the directory
Create a backup copy of the file ReportingServices.js
Edit the file. And append this to the bottom of it:
var jQueryScriptOutputted = false;
function initJQuery() {
//if the jQuery object isn't available
if (typeof(jQuery) == 'undefined') {
if (! jQueryScriptOutputted) {
//only output the script once..
jQueryScriptOutputted = true;
//output the script
document.write("<scr" + "ipt type=\"text/javascript\" src=\"../js/jquery-1.6.2.min.js\"></scr" + "ipt>");
}
setTimeout("initJQuery()", 50);
} else {
$(function() {
// Bug-fix on Chrome and Safari etc (webkit)
if ($.browser.webkit) {
// Start timer to make sure overflow is set to visible
setInterval(function () {
var div = $('table[id*=_fixedTable] > tbody > tr:last > td:last > div')
div.css('overflow', 'visible');
}, 1000);
}
});
}
}
initJQuery();
You can fix this easily with jQuery - and a little ugly hack :-)
I have a asp.net page with a ReportViewer user control.
<rsweb:ReportViewer ID="ReportViewer1" runat="server"...
In the document ready event I then start a timer and look for the element which needs the overflow fix (as previous posts):
<script type="text/javascript">
$(function () {
// Bug-fix on Chrome and Safari etc (webkit)
if ($.browser.webkit) {
// Start timer to make sure overflow is set to visible
setInterval(function () {
var div = $('#<%=ReportViewer1.ClientID %>_fixedTable > tbody > tr:last > td:last > div')
div.css('overflow', 'visible');
}, 1000);
}
});
</script>
Better than assuming it has a certain id.
You can adjust the timer to whatever you like. I set it to 1000 ms here.
FYI - none of the above worked for me in 2012 SP1...simple solution was to embed credentials in the shared data source and then tell Safari to trust the SSRS server site. Then it worked great! Took days chasing down supposed solutions like above only to find out integrated security won't work reliably on Safari - you have to mess with the keychain on the mac and then still wouldn't work reliably.
The solution provided by Emanuele worked for me. I could see the report when I accessed it directly from the server but when I used a ReportViewer control on my aspx page, I was unable to see the report. Upon inspecting the rendered HTML, I found a div by the id "ReportViewerGeneral_ctl09" (ReportViewerGeneral is the server id of the report viewer control) which had it's overflow property set to auto.
<div id="ReportViewerGeneral_ctl09" style="height: 100%; width: 100%; overflow: auto; position: relative; ">...</div>
I used the procedure explained by Emanuele to change this to visible as follows:
function pageLoad() {
var element = document.getElementById("ReportViewerGeneral_ctl09");
if (element) {
element.style.overflow = "visible";
}
}
I've used this. Add a script reference to jquery on the Report.aspx page. Use the following to link up JQuery to the microsoft events. Used a little bit of Eric's suggestion for setting the overflow.
$(document).ready(function () {
if (navigator.userAgent.toLowerCase().indexOf("webkit") >= 0) {
Sys.Application.add_init(function () {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack()) {
prm.add_endRequest(function () {
var divs = $('table[id*=_fixedTable] > tbody > tr:last > td:last > div')
divs.each(function (idx, element) {
$(element).css('overflow', 'visible');
});
});
}
});
}
});