Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance the ability of shiny and vue to communicate with each other #14

Open
kaipingyang opened this issue Jul 2, 2024 · 4 comments
Open

Comments

@kaipingyang
Copy link

As a shiny enthusiast, I am learning vue.

Thanks to vueR for letting us see the possibility of developing new shiny components based on shiny and vueR!

To make it easier to develop shiny components based on vueR, I think it is necessary to create new functions to enhance the ability of shiny and vue to communicate with each other

Ramnathv's vuer package https://github.com/ramnathv/vuer, inspired by the vueR, provides a set of functions to enhance shiny and vue's ability to communicate with each other:

Vue()
vueProxy()
vueUpdateData()

Unfortunately, this package has not been updated for five years.

Is it possible to incorporate his ideas into vueR?

@timelyportfolio
Copy link
Collaborator

@kaipingyang thanks so much for posting the issue and very happy/willing to consider new functionality. I had forgotten that Ramnath had done those experiments/extensions. Are there are any particular use cases or examples that you have in mind? I think #6, #7 (could swap out pinia for the deprecated vuex), #12 might be related.

@kaipingyang
Copy link
Author

Thanks for your reply. I will learn #6, #7, #12.

Here are a few use cases from the vuer package website, which still works with R4.4:

Vue -> Shiny

This example binds the Vue instance's data property name to shiny's input$name, making it easy to use Vue instance data in the server:

library(shiny)
library(vuer)
ui <- fluidPage(theme = shinythemes::shinytheme("cosmo"),
  tags$div(
    tags$label('Enter your name'),
    tags$input(type = "text", "v-model" = "name"),
    uiOutput("greeting")
  ) %>% 
  Vue(
    data = list(name_ = "")
  )
)


server <- function(input, output, session){
  output$greeting <- renderUI({
    tags$p(paste("Hello", input$name))
  })
}

shinyApp(ui = ui, server = server)

image

Shiny -> Vue

This example uses vueProxy and vueUpdateData in the server to pass the result of the input$plot_brush to the Vue data in the frontend, making it easy to change the Vue instance data in the server:

library(shiny)
library(ggplot2)
library(vuer)
ui <- fluidPage(theme = shinythemes::shinytheme("cosmo"),
  titlePanel(title = 'Shiny -> Vue'),
  mainPanel(
    plotOutput('plot', brush = brushOpts('plot_brush'), height = '300'),
    tags$pre("v-if" = "plot_brush !== null", 
      tags$code("{{plot_brush}}")
    ) %>% 
      Vue(data = list(plot_brush = c()), elementId = "app")
  )
)

server <- function(input, output, session){
  output$plot <- renderPlot({
    ggplot(mtcars, aes(x = mpg, y = wt)) +
      geom_point()
  })
  observeEvent(input$plot_brush, {
    vueProxy("app") %>% 
      vueUpdateData(plot_brush = input$plot_brush$coords_img)
  })
}
shinyApp(ui = ui, server = server)

image

@timelyportfolio
Copy link
Collaborator

timelyportfolio commented Jul 26, 2024

@kaipingyang hi, thanks for your patience. I have spent some time thinking through this and will relay my thoughts below. Also, I found a bug in vue3 that should be corrected in the dev branch, so please remotes::install_github("vue-r/vueR@dev") before trying.

Vue -> Shiny

I do not like the magical _ at the end of the variable especially with vue3. Watchers in vue3 can take many different forms and offer lots of options that are not available/workable with the magical _ approach. For instance, deep watchers and dot-delimited-paths are two that I use frequently. I prefer to leave watch to the user for full control. Nevertheless, I do agree that this package is sorely lacking documentation and examples that enable a user to watch effectively. I will try to resolve this over the weekend, but appreciate any help. Also, maybe we could write a helper function to reduce some of the boilerplate burden. For now, here is how we would replicate Ramnath's example with vue3.

library(shiny)
library(vueR)

ui <- fluidPage(
  theme = shinythemes::shinytheme("cosmo"),
  tags$div(
    id = "app",
    tags$label('Enter your name'),
    tags$input(type = "text", "v-model" = "name"),
    uiOutput("greeting"),
    tags$button('@click'="count++", "{{ count }}"),
    vue3(
      app = list(
        el = "#app",
        data = list(name = "", count = 0),
        watch = list(
          name = htmlwidgets::JS("function(newName, oldName) {Shiny.setInputValue('name', newName)}")
        )
      )
    )
  )
)


server <- function(input, output, session){
  output$greeting <- renderUI({
    tags$p(paste("Hello", input$name))
  })
}

shinyApp(ui = ui, server = server)

vueProxy / vueUpdateData

I am a big fan of the proxy mechanism and agree this would be a useful addition to the package. Dealing with nested data updates will be tricky though, and I probably will focus on the shallow update case.

@timelyportfolio
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants