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

Using more than one 'name' argument for on()? #3

Open
shahreyar-abeer opened this issue Aug 1, 2021 · 3 comments · May be fixed by #14
Open

Using more than one 'name' argument for on()? #3

shahreyar-abeer opened this issue Aug 1, 2021 · 3 comments · May be fixed by #14

Comments

@shahreyar-abeer
Copy link

shahreyar-abeer commented Aug 1, 2021

library(shiny)
library(gargoyle)
options("gargoyle.talkative" = TRUE)
ui <- function(request){
  tagList(
    h4('Go'),
    actionButton("y", "y"),
    actionButton("z", "z"),
    h4('Output of z$v'),
    tableOutput("evt")
  )
}

server <- function(input, output, session){
  
  # Initiating the flags
  init( "airquality", "iris", "renderiris", "a2")
  
  # Creating a new env to store values, instead of
  # a reactive structure
  z <- new.env()
  
  observeEvent( input$y , {
    z$v <- mtcars
    # Triggering the flag
    trigger("airquality")
  })
  
  observeEvent( input$y , {
    #z$v <- mtcars
    # Triggering the flag
    trigger("a2")
  })
  
  on("airquality", {
    # Triggering the flag
    z$v <- airquality
    trigger("iris")
  })
  
  on("iris", {
    # Triggering the flag
    z$v <- iris
    trigger("renderiris")
  })
  
  ## need to use both 'iris' & 'a2'
  on({"iris", "a2"},{
    print("observed!")
  })
  
  output$evt <- renderTable({
    # This part will only render when the renderiris
    # flag is triggered
    watch("renderiris")
    head(z$v) 
  })
  
}

shinyApp(ui, server)

Note: It doesn't work!

@DavidJesse21
Copy link

Hi, I'm not one of the package authors but since the functionality is actually quite simple, I think I'm still able to answer your "question".

Tl;dr:
For the functionality that you wish there won't be a solution that the package can provide (or at least not a simple one) and you might need to find your own way to accomplish your desired behaviour.

If you look at the source code of the init function:

gargoyle/R/funs.R

Lines 66 to 74 in e0398a6

init <- function(..., session = getDefaultReactiveDomain()){
lapply(
list(...),
function(x){
session$userData[[x]] <- reactiveVal(0)
}
)
}

you can actually see that it does nothing else than adding a reactive value to session$userData for each "flag" that you want to initialize.
Now, session$userData under the hood is an environment.
However, you cannot subset an environment which would be kind of required for your wish, but only extract single elements out of it which is what the {gargoyle} functions do and thereby "trigger" the events, when the reactive values in session$userData change.

And to be honest I don't really get the scenario that you have in mind, in which you need this functionality.
In the example you have given both actions are triggered by input$y, so you should be just fine with leaving out a2.

Hope I could help you.

Best Regards
David

@christiansegercrantz
Copy link

Hey,

I'm also interested in the feature, not by "and" but by "or". Shouldn't it be possible to see if either of the triggers change and based on that run the expression? I'm sorry if you explained this already but I at least couldn't grasp it from your explanation.

Br,
Christian

ilyaZar added a commit to ilyaZar/gargoyle that referenced this issue Mar 28, 2023
- provide an expression generator 'generate_watch_expr()' that parses
'name' arg to a list of reactives
- each element of this list is put into observeEvent
- if length(name) == 1, the default (previouis) behaviour is used
@ilyaZar
Copy link
Contributor

ilyaZar commented Mar 28, 2023

I am not sure if there is an "AND" case to implement since "AND" should be quite esoteric in the shiny-invalidation sense.

There may be a cleaner than #14 approach to provide the OR-case, though, as requested by the previous comment, but this one should work for the example of the initial issue; which is slightly modified so that a click on the z-button gives the trigger via a2 and a click on the y-button the previous triggering-chain.

Here is the testing example:

library(shiny)
library(gargoyle)

options("gargoyle.talkative" = TRUE)
ui <- function(request){
  tagList(
    h4('Go'),
    actionButton("y", "y"),
    actionButton("z", "z"),
    h4('Output of z$v'),
    tableOutput("evt")
  )
}

server <- function(input, output, session){

  # Initiating the flags
  init( "airquality", "iris", "renderiris", "a2")

  # Creating a new env to store values, instead of
  # a reactive structure
  z <- new.env()

  observeEvent(input$y , {
    z$v <- mtcars
    # Triggering the flag
    trigger("airquality")
  })

  observeEvent(input$z , {
    #z$v <- mtcars
    # Triggering the flag
    trigger("a2")
  })

  on("airquality", {
    # Triggering the flag
    z$v <- airquality
    trigger("iris")
  })

  on("iris", {
    # Triggering the flag
    z$v <- iris
    trigger("renderiris")
  })

  ## need to use both 'iris' & 'a2'
  on(c("iris", "a2"),{
    print("observed!")
  })

  output$evt <- renderTable({
    # This part will only render when the renderiris
    # flag is triggered
    watch("renderiris")
    head(z$v)
  })

}
shinyApp(ui, server)

@ilyaZar ilyaZar linked a pull request Jul 4, 2023 that will close this issue
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

Successfully merging a pull request may close this issue.

4 participants