Reading javascript variable into shiny/R on app lo

2019-01-23 10:16发布

问题:

What I want to do is get the user ID from a wordpress logged-in user when I load a shiny app in an iframe. This variable could then be used to save and modify user-specific data.


I have gotten some of the way by adding the following code to the wordpress page:

<?php global $current_user; 
get_currentuserinfo(); 
$user_name = $current_user->user_login; 
$user_ID = get_current_user_id(); 
?>

And then this to make it a javascript variable:

<script type="text/javascript"> 
var username = <?php echo json_encode($user_name) ?> ; 
var userID = <?php echo json_encode($user_ID) ?> ; 
</script>




Using the example found here I am able to get the variable if I click a div box.

ui.R:

library(shiny)

shinyUI( bootstrapPage(

  # include the js code
  includeScript("get_user_id.js"),

  # a div named mydiv
  tags$div(id="mydiv",
           style="width: 50px; height :50px; left: 100px; top: 100px;
           background-color: gray; position: absolute"),

  # an element for unformatted text
  verbatimTextOutput("results")
))

server.R:

shinyServer(function(input, output, session) {
  output$results = renderPrint({
    input$mydata
  })
})

get_user_id.js:

$(document).ready(function() {
  document.getElementById("mydiv").onclick = function() {
  document.domain = "DOMAIN_NAME_HERE"; 
  var username = parent.username; 
  var userID = parent.userID; 
    Shiny.onInputChange("mydata", userID);
  };
});



Note that the domain name (or IP) is needed because the shiny app loaded in the iframe is on another port than the wordpress page. The iframe should be created by:

<script type="text/javascript"> 
document.domain = "DOMAIN_NAME_HERE"; 
</script> 
<iframe id="example1" style="border: none; width: 100%; height: 500px;" src="APP_URL" height="150" frameborder="0"></iframe>




But what I want is to just get the variable as soon as the app loads so I can use it in the app to save data to a database etc.
I couldn't find any way to do this. I haven't been able to achieves this using ".onload" or several jquery alternatives I have tried. Any hints would be highly appreciated.




EDIT: Also posted here: https://groups.google.com/forum/#!topic/shiny-discuss/3XM2mHuzqRs

回答1:

Erik Westlund was kind enough to provide the following solution.


get_user_id.js:

document.domain = "MYDOMAIN.com"; 

var userIDVariableName = parent.userID; 
var userID = document.getElementById("userID"); 
userID.value = userIDVariableName; 

var usernameVariableName = parent.username; 
var username = document.getElementById("username"); 
username.value = usernameVariableName;

As mentioned above remember to change the domain. And set it in the page loading the iframe.


ui.R:

library(shiny) 

shinyUI( bootstrapPage( 

# Hidden input boxes to save the variable to 
HTML(‘ <input type="text" id="userID" name="userID" style="display: none;"> ‘), 
HTML(‘ <input type="text" id="username" name="username" style="display: none;"> ‘), 


# include the js code 
includeScript("get_user_id.js"), 

# Show the output 
textOutput("view") 
))

Change the path to the script as needed.


server.R:

shinyServer(function(input, output, session) { 



userID <- reactive({ input$userID }) 
username <- reactive({ input$username }) 

output$view <- renderText( paste0( "User ID is: ",userID()," and username is: ",username() ) ) 

})


Add this to the page containing the iframe:

PHP to get the variable from wordpress.

<?php global $current_user; 
get_currentuserinfo(); 
$user_name = $current_user->user_login; 
$user_ID = get_current_user_id(); 
?>

And then this to make it a java variable:

<script type="text/javascript"> 
var username = <?php echo json_encode($user_name) ?> ; 
var userID = <?php echo json_encode($user_ID) ?> ; 
</script>

Set domain and the iframe:

<script type="text/javascript"> 
document.domain = "MYDOMAIN.com"; 
</script> 
<iframe id="example1" style="border: none; width: 100%; height: 500px;" src="PATH_TO_SHINY_APP" width="300" height="150" frameborder="0"></iframe>


回答2:

If you want to call onInputChange as soon as the Shiny app starts then you need to use the following JavaScript code instead of listening for click events.

$(function() {
  setTimeout(function() {
    Shiny.onInputChange("mydata", userID);
  }, 10)
});