The Shiny app below redirects to Google as soon as you press the button 'Submit'. I would like a similar app that redirects to two URLs (in sequence). So, for example it would go to "https://www.google.com" first and then to "https://www.stackoverflow.com". Is this possible?
library(shiny)
jscode <- "Shiny.addCustomMessageHandler('mymessage', function(message) { window.location = message;});"
ui <- fluidPage(
tags$head(tags$script(jscode)),
actionButton("submit", "Submit")
)
server <- function(input, output, session) {
observeEvent(input$submit, {
url <- "https://www.google.com"
session$sendCustomMessage("mymessage", url)
})
}
shinyApp(ui,server)
jscode <- "Shiny.addCustomMessageHandler('redirect', function(URLS) {
for (var i = 0; i < URLS.length; i++) {
setTimeout(function() {
var a = document.createElement('a');
a.style.display = 'none';
a.href = URLS[i];
a.target = '_blank';
document.body.appendChild(a);
a.click();
a.remove();
}, i * 500);
}
});"
observeEvent(input$submit, {
urls <- list("https://www.google.com", "https://www.stackoverflow.com")
session$sendCustomMessage("redirect", urls)
})
Related
Seems like shiny cannot recognize my .js file. Question is why?
Inlined js script text runs smoothly:
library(shiny)
header = dashboardHeader(disable = TRUE)
sidebar = dashboardSidebar(disable = TRUE)
body = dashboardBody(
shiny::tags$script(
HTML("document.body.style.backgroundColor = 'skyblue';")),
)
ui = dashboardPage(header = header, sidebar = sidebar, body = body)
server = function(input, output, session){
}
shinyApp(ui, server)
However when i embedd my .js file (myscript.js stored within www subdirectory)
document.body.style.backgroundColor = "skyblue";
$("firstinput").on("keypress", function(){
alert("Pressed");
})
$(document).on('shiny:connected', function(event) {
alert('Connected to the server');
})
...like this:
library(shiny)
header = dashboardHeader(disable = TRUE)
sidebar = dashboardSidebar(disable = TRUE)
body = dashboardBody(
shiny::tags$head(
shiny::tags$script(
src = "myscript.js"
)),
HTML('<input type="button" id="firstinput">')
)
ui = dashboardPage(header = header, sidebar = sidebar, body = body)
server = function(input, output, session){
}
shinyApp(ui, server)
nothing is applied... How comes?
No need of tags$head(). The following works fine.
tags$script(src = "myscript.js")
I have a shiny app that I would like to end the session every time, I close the browser. I researched around and most developers proposed adding this snippet on my server.
session$onSessionEnded(function() {
stopApp()
})
A minimal example is provided below;
rm(list=ls())
library(shiny)
doshiny <- function() {
app=shinyApp(
ui = fluidPage(
textInput("textfield", "Insert some text", value = "SomeText")
),
server = function(input, output, session) {
session$onSessionEnded(function() {
stopApp()
})
}
)
runApp(app)
}
openshiny <- function() {
doshiny()
print("Finished.")
}
openshiny()
the problem with this example I keep asking myself where should I place my other the other lines in the server? for instance, if I want to plot a histogram which way do I write my server?
is it
server = function(input, output, session) {
session$onSessionEnded(function() {
hist(data)
stopApp()
})
}
)
or
server = function(input, output, session) {
hist(data)
session$onSessionEnded(function() {
stopApp()
})
}
)
I am just seeking a more working example
If you want to plot your histogram while the session is active, take the second option. As mentioned by #Waldi the first option plots your histogram when the session is ended, and the user will thus never see the histogram. See here an example of the two options:
First option: we never see the table
rm(list=ls())
library(shiny)
doshiny <- function() {
app=shinyApp(
ui = fluidPage(
textInput("textfield", "Insert some text", value = "SomeText"),
dataTableOutput('table')
),
server = function(input, output, session) {
session$onSessionEnded(function() {
output$table <- renderDataTable(iris)
stopApp()
})
}
)
runApp(app)
}
openshiny <- function() {
doshiny()
print("Finished.")
}
openshiny()
Second option: we see the table
rm(list=ls())
library(shiny)
doshiny <- function() {
app=shinyApp(
ui = fluidPage(
textInput("textfield", "Insert some text", value = "SomeText"),
dataTableOutput('table')
),
server = function(input, output, session) {
output$table <- renderDataTable(iris)
session$onSessionEnded(function() {
stopApp()
})
}
)
runApp(app)
}
openshiny <- function() {
doshiny()
print("Finished.")
}
openshiny()
I'm building a Shiny app that lets users upload images to the server. I'd like to display the image on the screen without having to upload it first and then get the rendered output back. Is this possible?
This is my code right now. You can select an image file, which gets uploaded. The image is then rendered from the file on the server side, after it's been received. I'd like to avoid the roundtrip.
UI
fluidPage(
titlePanel("File upload"),
sidebarLayout(
sidebarPanel(
fileInput("img", "Choose image file",
accept=c("image/jpeg", "image/x-windows-bmp"))
),
mainPanel(
imageOutput("picture", width="500px", height="500px")
)
)
)
Server
function(input, output, session)
{
output$picture <- renderImage({
imgFile <- input$img
if(is.null(imgFile))
return(list(src=""))
list(src=imgFile$datapath, alt=imgFile$name, contentType=imgFile$type)
}, deleteFile=FALSE)
# do more stuff with the file
}
You can use package shinyjs to call FileReader from HTML 5 read here
library(shinyjs)
shinyApp(ui = fluidPage(
useShinyjs(),
titlePanel("File upload"),
sidebarLayout(
sidebarPanel(
fileInput("img", "Choose image file",
accept=c("image/jpeg", "image/x-windows-bmp")),
HTML('<output id="list"></output>')
),
mainPanel(
imageOutput("picture", width="500px", height="500px")
)
)),
server = function(input, output, session){
shinyjs::runjs("
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class=\"thumb\" src=\"', e.target.result,
'\" title=\"', escape(theFile.name), '\"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('img').addEventListener('change', handleFileSelect, false);")
output$picture <- renderImage({
imgFile <- input$img
if(is.null(imgFile))
return(list(src=""))
list(src=imgFile$datapath, alt=imgFile$name, contentType=imgFile$type)
}, deleteFile=FALSE)
})
Edit:
Okay, I now the question is clear for me, I hope :).
The problem is that pictures are added within <output id="list"></output>. So I would suggest clearing it before a new picture is added with: document.getElementById('list').innerHTML = ''
library(shiny)
library(shinyjs)
shinyApp(ui = fluidPage(
useShinyjs(),
titlePanel("File upload"),
sidebarLayout(
sidebarPanel(
fileInput("img", "Choose image file",
accept=c("image/jpeg", "image/x-windows-bmp"))
),
mainPanel(
HTML('<output id="list"></output>')
)
)),
server = function(input, output, session){
shinyjs::runjs("
function handleFileSelect(evt) {
document.getElementById('list').innerHTML = ''
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class=\"thumb\" src=\"', e.target.result,
'\" title=\"', escape(theFile.name), '\"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('img').addEventListener('change', handleFileSelect, false);")
})
I have the following service call to download files from the server. I currently have it so that PDFs will open up in a new tab/window, and any other document types will be downloaded.
The problem I'm having right now is that the PDF is being prevented by a pop up blocker. Is there any way around this?
return formService.getForm(params)
.$promise
.then(response => {
var blob = new Blob([response.data], {
type: response.responseType
});
var fileUrl = (window.URL || window.webkitURL).createObjectURL(blob);
if (response.responseType === 'application/pdf') {
window.open(fileUrl);
} else {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none"
a.href = fileUrl;
a.download = formName;
a.target = "_blank";
a.click();
window.URL.revokeObjectURL(fileUrl);
}
})
.catch(error => {
console.error(`Error downloading form '${formName}' `, error);
});
I found an answer to my question via another stack overflow post.
window.open popup getting blocked during click event
Basically, i call var newWindow = window.open(); before I make the service call and then newWindow.location = fileUrl in the success callback.
I have three different js files for three different sites. Let me preface by saying the manifest does have the proper settings to have these these on the proper sites, and only one function of the extension (the most important one) does not work.
The first, which works, is for pages like these: http://hearthstonetopdeck.com/deck.php?d=1613
var decklist = [];
$('.cardname').each(function(i, el) {
var values = $(this).text().split(' ');
var count = parseInt(values.shift(), 10);
for (var i = 0; i < count; i++) {
decklist.push(values.join(' '));
}
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
var html = $('#deckname').html() + '';
fileName = $('#deckname').text() + '.txt';
html = html.replace(/<h1>#/, '<h1><a class="download" href="#download">DOWNLOAD</a> - #');
$('#deckname').html(html);
});
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
Running this in the console will work just as it does with the extension. I have tested all 3 of these js files both using the chrome extension method and pasting in the console. Results are identical.
The second site (http://www.hearthhead.com/deck=300/spell-power-on-a-budget), for which it USED to work, no longer does. I can't seem to remember change any code either, and it should fire identically. The issue here is that, while the download link appears, either the event doesn't fire or it simply doesn't work. Here is the code for site #2:
var decklist = [];
$('.deckguide-cards-type li').each(function(i, el) {
var values = $(this).text().substring(1).split(' ');
if ($.inArray("x2", values) != "-1") {
values.pop();
decklist.push(values.join(' '));
}
decklist.push(values.join(' '));
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
$(document).ready(function(){
var html = $('.text h1').html() + ' hearthstonedeckdl';
fileName = $('.text h1').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '- <a class="download" href="#download">DOWNLOAD</a>');
$('.text h1').html(html);
});
Firing the function saveData on load DOES work exactly as expected, and a .txt file is downloaded with the proper data. This is the intended function on clicking the download link, and it works in the first example.
This final example has not worked period, but as before, firing on load works, properly. It's simply the link I'm having issues with. The site is here: http://www.hearthpwn.com/decks/46364-d3managements-legend-hunter
The code is below:
var decklist = [];
$('.col-name').each(function(i, el) {
var values = $(this).text().substring(2).substring(0, $(this).text().length - 10).replace(/[^a-zA-Z0-9\.\s']+/g ,"").split(' ');
if ($.inArray("", values) != "-1") {
return;
} else if ($(this).text().substr($(this).text().length - 3, 1) == "2") {
decklist.push(values.join(' '));
decklist.push(values.join(' '));
} else {
decklist.push(values.join(' '));
}
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
$(document).ready(function(){
var html = $('.t-deck-title').html() + ' hearthstonedeckdl';
fileName = $('.t-deck-title').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '</br><a class="download" href="#download">DOWNLOAD</a>');
$('.t-deck-title').html(html);
});
I'm fairly new to jQuery, but consulting with a friend of mine that has more experience than me can't seem to find the issue, and it's driving me absolutely mad.
Thanks!
You declare a click event on an anchor before it is created.
Replace this:
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
With this:
$(document).ready(function(){
$(document).on('click', 'a[href="#download"]', function(){
saveData(data, fileName);
});
});
Or keep your code and make sure you call this:
var html = $('.t-deck-title').html() + ' hearthstonedeckdl';
fileName = $('.t-deck-title').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '</br><a class="download" href="#download">DOWNLOAD</a>');
$('.t-deck-title').html(html);
before attaching the click event.
Have you tried giving jquery another namespace? I noticed on the site you provided does not run jquery which might mean on the other sites it may be conflicting.
try
var $jg = jQuery.noConflict();
at the top of your document.
Then instead of
$('.t-deck-title')
try
$jg('.t-deck-title')