How to execute a script after the output rendering ?

3,422 views
Skip to first unread message

julie...@gmail.com

unread,
Mar 28, 2014, 11:26:07 AM3/28/14
to shiny-...@googlegroups.com
Hi,

I wonder how I can execute a script after the server render the outputs ?

shiny::runApp(list(
  ui = basicPage(
    tags$head(tags$script(type = "text/javascript",
                          "$(document).ready(function() {
                            alert(document.getElementById(
'test').value);
                          });")),
    verbatimTextOutput("test")
  ),
  server = function(input, output, session) {
    output$test <- renderPrint({
      return("test")
    })
  }
))

I guess that $(document).ready(function() or $(window).load(function() or tags$body(onload = 'myfunction()') are irelevant because the server renders the outputs once the dom is ready ? 

A concrete example based on another question : (https://groups.google.com/forum/#!topic/shiny-discuss/PvlrXLEo0z8)

I would like to use jquery for condiotional formating :

shiny::runApp(list(
  ui = bootstrapPage(
    tags$head(tags$script(type = "text/javascript", "$(document).ready(function() {
                           
                            $('td').each(function() {

                              var color = $(this).text();
                           
                              if (color == ' green ') {
                                $(this).css('background-color', '#0c0');
                              }
                              else if (color == ' red ') {
                                $(this).css('background-color', '#f00');
                              }
                            })
      });")),
      tableOutput("my_dataframe")
     
  ),
  server = function(input, output) {
    output$my_dataframe <- renderTable({
      data.frame("Brand ID"=1:4,"Client1"=c("red", "green", "green", "green"),
                 "Client2"=c("green", "red", "green", "red"))
    })
  }
  )
)

Here i would to conditionnal formating the cells of a table but nothing happened, I think beacause the script execute before that the table "exists" in the document ? Because when I set this function for an evenment (a click for example, cf the function bellow) it works.
 (I'm no very pro with jquery tho..)

$(document).ready(function() {
                           
                            $(document).on('click', 'td', function(evt) {
                              var color = $(this).text();
                           
                              if (color == ' green ') {
                                $(this).css('background-color', '#0c0');
                              }
                              else if (color == ' red ') {
                                $(this).css('background-color', '#f00');
                              }
                            })
});

Thanks for any help.
(Sorry for english and explanations I tried my best...)

Stéphane Laurent

unread,
Mar 28, 2014, 12:11:45 PM3/28/14
to shiny-...@googlegroups.com
I think the easiest way is to render your table with renderUI and to send the javascript in this renderUI with  session$sendCustomMessage. 
See here an example of  session$sendCustomMessage : https://groups.google.com/d/topic/shiny-discuss/oJo3SiCfXTs/discussion

Joe Cheng

unread,
Mar 28, 2014, 2:51:11 PM3/28/14
to Stéphane Laurent, shiny-...@googlegroups.com
That's not a bad idea, Stéphane.

Another way to go would be to use

session$onFlushed(function() {
  session$sendCustomMessage(...)
})



On Fri, Mar 28, 2014 at 9:11 AM, Stéphane Laurent <lauren...@yahoo.fr> wrote:
I think the easiest way is to render your table with renderUI and to send the javascript in this renderUI with  session$sendCustomMessage. 
See here an example of  session$sendCustomMessage : https://groups.google.com/d/topic/shiny-discuss/oJo3SiCfXTs/discussion

--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

julie...@gmail.com

unread,
Mar 29, 2014, 6:35:26 AM3/29/14
to shiny-...@googlegroups.com
Many thanks Joe and Stéphane !!

I finally used the 2nd solution, it's perfect :)

script <- "$('td').each(function() {

              var cell = $(this).text();
          
              if (cell == ' green ') {

                $(this).css('background-color', '#0c0');
              }
              else if (cell == ' red ') {

                $(this).css('background-color', '#f00');
              }
            })"

shiny::runApp(list(
  ui = bootstrapPage(
    tags$head(tags$script(HTML('Shiny.addCustomMessageHandler("jsCode", function(message) { eval(message.value); });'))),
    tableOutput("test")

  ),
  server = function(input, output, session) {
    session$onFlushed(function() {
      session$sendCustomMessage(type='jsCode', list(value = script))
    })
    output$test <- renderTable({
      data.frame(c1 = c("green", "red", "green", "green", "red"))
    })
  }
))

Stéphane Laurent

unread,
Mar 29, 2014, 7:15:06 AM3/29/14
to shiny-...@googlegroups.com
thank you for sharing the solution

Shane Varn

unread,
Mar 3, 2017, 12:39:23 PM3/3/17
to Shiny - Web Framework for R
This thread was helpful. However, I am regularly updating a table in my application. I tried the 'onFlushed' method, changing the 'once' argument to False. This got the job done however, lagged my application every time other reactive elements were updated. This was my solution to ensure that my javascript was only run when my table was updated:

library(shiny)
script <- "$('td').each(function() {
var cell = $(this).text();
if (cell == ' green ') {
$(this).css('background-color', '#0c0');
}
else if (cell == ' red ') {
$(this).css('background-color', '#f00');
}
})"
shiny::runApp(list(
  ui = bootstrapPage(
    tags$head(tags$script(HTML( 
      "Shiny.addCustomMessageHandler('jsCode', function(message) {
        $('table.test').replaceWith(message.custom_table);
        eval(message.value);
      });"))),
    div(align='center',
    selectInput("input1",NULL, c("green", "red")),
    selectInput("input2",NULL, c("green", "red")),
    selectInput("input3",NULL, c("green", "red")),
    selectInput("input4",NULL, c("green", "red")),
    selectInput("input5",NULL, c("green", "red")),
    HTML("<table class='test'></table>")

    )
  ),
  server = function(input, output, session) {
   
    observe({
      custom_table <- data.frame(c1 = c(input$input1, input$input2, input$input3, input$input4, input$input5))
      custom_table <- print(xtable(custom_table),  type="html", html.table.attributes="class='test'")
     
      session$sendCustomMessage(type='jsCode', list(value = script, custom_table = custom_table))
    })
   
  }
))

David Lukeš

unread,
Jun 5, 2017, 1:29:47 PM6/5/17
to Shiny - Web Framework for R

I’m glad I found this thread but ended up doing something a little bit different, so here’s an alternative in case someone might find it useful: you can listen to the shiny:value event and when it occurs, prevent the default behavior (= just rendering the output from the server) and update the UI manually, incorporating your custom code:

$(document).on("shiny:value", function(e) {
  if (e.name == "mytable") {  // mytable is the name / id of the output element
    e.preventDefault();
    $("#mytable")
      .removeClass("shiny-output-error")  // get rid of potential previous error styling
      .html(e.value)  // render the output from the server
      .find("td")
      .each(colorize);  // run custom javascript on the rendered output
  }
});
Reply all
Reply to author
Forward
0 new messages