Search code examples
javascriptrshiny

Implementing JavaScript in Shiny Modules


I have a shiny app which generates trend lines of a timeseries data. In the app its using JavaScript code to get the Time zone so that it can be used to make sure the timeseries data can be converted to local time zone.

Problem : Trend Line is not showing but in the browser console : Time Zone is being displayed.

Below is the Sample Code :

library(shiny)
library(shinyjs)
library(plotly)
library(dplyr)
library(lubridate)

# JavaScript code
jsCode <- '
shinyjs.getClientTimezone = function() {
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  Shiny.setInputValue("client_timezone", timezone);
  console.log("Client Timezone", timezone);
}'

# Module UI
mod_trend_chart_ui <- function(id) {
  ns <- NS(id)
  tagList(
    shinyjs::useShinyjs(),
    shinyjs::extendShinyjs(text = jsCode, functions = "getClientTimezone"),
    plotlyOutput(ns("trend_chart"))
  )
}

# Module Server
mod_trend_chart_server <- function(id, raw_data, processed_data) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    
    observe({
      shinyjs::runjs(jsCode)
      shinyjs::js$getClientTimezone()
    })
    
    client_timezone <- reactive({
      req(input$client_timezone)
      print(paste("Received client timezone:", input$client_timezone))
      input$client_timezone
    })
    
    observe({
      print(client_timezone())
    })
    
    output$trend_chart <- renderPlotly({
      timezone <- client_timezone()
      req(timezone)
      
      raw <- raw_data()
      processed <- processed_data()
      
      if (nrow(raw) == 0 && nrow(processed) == 0) {
        return(plot_ly() %>%
                 layout(title = "No data available."))
      } else {
        p <- plot_ly() %>%
          add_trace(
            data = raw, x = ~utc_timestamp, y = ~value, name = "Raw Data", type = "scatter", mode = "lines",
            line = list(color = "#f69a8e", shape = "hv"),
            hovertemplate = "Timestamp:%{x}<br>Value:%{y:.2f}"
          ) %>%
          add_trace(
            data = processed, x = ~utc_timestamp, y = ~value, name = "Processed Data", type = "scatter", mode = "lines",
            line = list(color = "#6bbcf3", shape = "hv"),
            hovertemplate = "Timestamp:%{x}<br>Value:%{y:.2f}"
          )
        
        return(p)
      }
    })
  })
}

# Sample data
raw_data_sample <- data.frame(
  utc_timestamp = as.POSIXct(c("2023-06-01 10:00:00", "2023-06-01 11:00:00", "2023-06-01 12:00:00")),
  value = c(10, 20, 30)
)

processed_data_sample <- data.frame(
  utc_timestamp = as.POSIXct(c("2023-06-01 10:00:00", "2023-06-01 11:00:00", "2023-06-01 12:00:00")),
  value = c(15, 25, 35)
)

# Main UI
ui <- fluidPage(
  mod_trend_chart_ui("trendChart")
)

# Main Server
server <- function(input, output, session) {
  raw_data <- reactiveVal(raw_data_sample)
  processed_data <- reactiveVal(processed_data_sample)
  
  mod_trend_chart_server("trendChart", raw_data, processed_data)
}

# Run the app
shinyApp(ui, server)

Solution

  • You can pass the id to getClientTimezone function. Try this

    # JavaScript code
    jsCode <- '
    shinyjs.getClientTimezone = function(id) {
      const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
      Shiny.setInputValue(id+"-"+"client_timezone", timezone);
      console.log("Client Timezone", timezone);
    }'
    
    # Module UI
    mod_trend_chart_ui <- function(id) {
      ns <- NS(id)
      tagList(
        shinyjs::useShinyjs(),
        shinyjs::extendShinyjs(text = jsCode, functions = "getClientTimezone"),
        plotlyOutput(ns("trend_chart"))
      )
    }
    
    # Module Server
    mod_trend_chart_server <- function(id, raw_data, processed_data) {
      moduleServer(id, function(input, output, session) {
        ns <- session$ns
        
        observe({
          shinyjs::runjs(jsCode)
          shinyjs::js$getClientTimezone(id)
        })
        
        client_timezone <- reactive({
          req(input$client_timezone)
          print(paste("Received client timezone:", input$client_timezone))
          input$client_timezone
        })
        
        observe({
          print(client_timezone())
        })
        
        output$trend_chart <- renderPlotly({
          timezone <- client_timezone()
          # req(client_timezone())
          
          raw <- raw_data()
          processed <- processed_data()
          
          if (nrow(raw) == 0 && nrow(processed) == 0) {
            return(plot_ly() %>%
                     layout(title = "No data available."))
          } else {
            p <- plot_ly() %>%
              add_trace(
                data = raw, x = ~utc_timestamp, y = ~value, name = "Raw Data", type = "scatter", mode = "lines",
                line = list(color = "#f69a8e", shape = "hv"),
                hovertemplate = "Timestamp:%{x}<br>Value:%{y:.2f}"
              ) %>%
              add_trace(
                data = processed, x = ~utc_timestamp, y = ~value, name = "Processed Data", type = "scatter", mode = "lines",
                line = list(color = "#6bbcf3", shape = "hv"),
                hovertemplate = "Timestamp:%{x}<br>Value:%{y:.2f}"
              )
            
            return(p)
          }
        })
      })
    }
    

    output