How do I use {polished} package with {brochure} framework? - r

This was a complicating in logic execution i came across using {polished} and {brochure}.
When placing secure_ui/secure_server inside of a brochure::Page() in the same order of the example given by the {polished} dev team, there are changes to how a Shiny App is deploy on the {brochure} infrastructure. I was not sure where to relocate the polsiehd logic to.
Differences
no global.R file in a brochureApp()
multiple calls to different module_ui/server functions since each brochure::page() is its owns shiny session
single page shinyApp vs true multipage shinyApp

When needing to merge the two logics you must:
move polished_config() in globals.R --> golem::runApp() [initiate global setting for brochureApp()]
run_app <- function(
onStart = NULL,
options = list(),
enableBookmarking = NULL,
...
) {
# old 'globals.R' logic
polished_config(
app_name = "humblFinance",
api_key = "xxxx"
)
with_golem_options(
app = brochureApp(
# Putting the resources here
golem_add_external_resources(),
page1(),
),
golem_opts = list(...)
)
}
wrap each brochure::page() ui/server with polished::secure_ui/server()`
# an example login page
login <- function(id = "login", href = "/login") {
page(
href = href,
ui = secure_ui(
mod_login_ui(id = id),
sign_in_page_ui = sign_in_custom()
),
server = secure_server(
function(input, output, session) {
mod_login_server(id = id)
}
)
)
}
NOTE
sign_in_custom() is a function that returns a customized UI object from polished::sign_in_default() to create personal business webpages.
I would recommend wrapping polished::sign_in_default() in a custom global function since you will need to define this on ever brochure::page() that you want to have protected behind polished auth.
once you authenticate one page through polished, you will be able to access all other protected pages while you are still logged in. After loggign out and attempting to access any one of the protected pages will result in a custom login page

Related

State management with jQuery access

How can a user defined app state be stored using R Shiny so that it is both accessible in R code and in jQuery code?
For example, my app has two states black and white. Options for storing the current state include
as hidden text in the DOM
as a data attribute of an DOM element
use local storage on the browser
Is there a better approach that is built in to Shiny for this purpose? Something like having a global variable defined in R that can be read in jQuery without having to send a message.
The canonical approach to communicate with JavaScript is indeed via sending a message.
Of course you can rely on pure HTML <-> JS communication means as well:
library(shiny)
read_js <- "$(function() {
$('#output').append(`Text from data: ${$('#constant_data').data('state')}`,
$('<br>'),
`Text from hidden: ${$('#constant_hidden').text()}`,
$('<br>'),
`Text from session: ${sessionStorage.getItem('constant_session')}`,
$('<br>'),
`Text from window: ${window.state}`);
});
"
ui <- fluidPage(
tags$head(tags$script("sessionStorage.setItem('constant_session', 'black');
window.state = 'black';")),
tags$head(tags$script(HTML(read_js))),
div(id = "constant_data", `data-state` = "black"),
div(id = "constant_hidden", "black", style = "display: none"),
div(id = "output"),
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
And the choice of the method is up to you.
Some questions which may guide your choice:
Should the state by visible in the DOM?
Does the state change over time?
Should the state be persistent over sessions?

R Shiny - Trigger a shinyalert popup directly from the UI using javascript

With the following piece of code I'm able to trigger a pure javascript alert by clicking on the question-mark of the fileInput:
fileInput('peptides',
span("Peptides file ",
id="peptidesSpan",
tags$a(
tags$i(class='fa fa-question-circle'),
href = "#",
onclick = "alert('Oops!'); return false;")
),
multiple=FALSE,
accept = c('text/csv','text/comma-separated-values',
)
)
I was wondering if I could trigger a shinyalert popup (https://github.com/daattali/shinyalert/) instead of a simple javascript alert directly form the UI without any observer in the server side.
Something like:
shinyalert("Oops!", "Something went wrong.", type = "error")
If there is not a workaround to do that, any other suggestion with an observer would be welcome as well.
I think using an observer is not at all inconvenient.
Instead of alert(), invoke Shiny.setInputValue(id, value);, and then on your server side you can observeEvent(input[id], { shinyalert() }).
Read this article for details: https://shiny.rstudio.com/articles/communicating-with-js.html
You only need to use one observe code block to achieve this.
An example
Define a customized function in your UI Javascript code and call it in your onclick.
You can put this function say in helper.js in the 'www' folder in your project folder, that will be www/helper.js. Include this file in your Shiny UI code by tags$head(tags$script(src = "helper.js"))
function showAlert(message, type = "info") {
Shiny.setInputValue(
'alertMessage',
{
message: message,
type: type
},
{ priority: 'event' }
);
}
Then on the Shiny server side define the observer once
observeEvent(input$alertMessage, {
alertData <- input$alertMessage
req(alertData)
shinyalert("title", alertData$message, type = alertData$type)
})
It's one of the few times that I answer my own post, but after searching a bit more on stack-overflow I found a workaround inspired by this post.
I downloaded the sweetAlert.js file of the Sweet Alert library directly from here
I create a www folder in the root of my Shiny application
I added the sweetAlert.js file in the www directory and in the dashboardBody() of the ui.R I added the following line:
tags$head(tags$script(src="sweetAlert.js"))
Now I'm able to call directly the Swal.fire function with any argument as I would normally do in any other framework which runs javascript.

Pass combobox value from view to controller using #Html.ActionLink

I have a kendo.combobox() control on my Layout.cshtml page which is a list of projects.
#(Html.Kendo().ComboBox()
.Name("projects")
.Placeholder("select project")
.DataTextField("Text")
.DataValueField("ID")
.HtmlAttributes(new { style = "width:45%;" })
.Filter("contains")
.SelectedIndex((int)Session["ProjectNoIndex"])
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetProjectsList", "Home");
})
.ServerFiltering(true);
})
)
I have a menu as well in the Layout.cshtml which is created using #Html.ActionLinks (one sample below).
<li>#Html.ActionLink("Documents", "Search", "Document", new { projectNo = 1}, new {#id = "send"})</li>
Search action in Document controller and most other actions in the application expect the projectNo parameter (entire application works based on the selected project of the user). So, I thought of saving the selected ProjectNo in Session but if I do this then users can only work with 1 project even if they open the application in multiple tabs/windows in a single browser (sessions are shared across tabs/windows).
So, I thought of passing the selected ProjectNo using querystrings. I tried below, which worked fine except when user right clicks and open's the link in new tab. in such case, below click event does not fire.
$('#send').click(function () {
var x = $("#projects").data("kendoComboBox").selectedIndex;
var url = '#Url.Action("Search", "Document", new { projectNoIndex = "-1" })'
url = url.replace("-1", x);
this.href = url;
});
I don't want to restrict user by oncontextmenu = "return false;" option either. What are my options here?
Q1: How can I make sure I can pass the selected ProjectNo using querystring
Q2: Is there any other alternative to Session where I can persist the project information across tabs/windows which can be easily available in the entire application per user, per tab/window.

Use R Scipt to Login to Web site and perform some kind of action

How can I use R to login to a web site and perform some action? I think the code below is very close, but something seems to be off here.
library(httr)
library(XML)
handle <- handle("http://subscribers.footballguys.com")
path <- "amember/login.php"
# fields found in the login form.
login <- list(
amember_login = "username"
,amember_pass = "password"
,amember_redirect_url =
"https://www.google.com/accounts/Login"
)
THEN
response <- POST(handle = handle, path = path, body = login)
Any insight into this would be most appreciated.

Deploy a shiny app - reactiveValues not found

I am trying to deploy my shiny app on shinyapps.io. The app runs fine in my console but when I deploy my app I get errors for reactiveValues, such as:
object 'Logged' not found
OR
Error in reactiveValues(Logged = Logged, registed = registed, Foget = Foget, : object 'Logged' not found
My script is more than 1000 lines, so, I was not sure that it is a good way to upload the whole script, that's why I decided to put the first few lines from the server that are about the reactiveValues.
Appriciate!
server = (function(input, output,session) {
Logged = FALSE;
registed = FALSE;
Foget = FALSE;
Started = FALSE;
tested = FALSE;
Saved = FALSE;
USER <- reactiveValues(Logged = Logged,registed = registed, Foget=Foget, Started=Started,tested=tested,Saved=Saved)
...
...
...
Declare it as global variable using "<<-" I would suggest you to declare all variable as global variable.
The code should end by the following line:
shinyApp(ui = ui, server = server)

Resources