Modify an object to respond to "event-like" reactive inputs, values, and
expressions. bindEvent()
can be used with reactive expressions, render
functions, and observers. The resulting object takes a reactive dependency on
the ...
arguments, and not on the original object's code. This can, for
example, be used to make an observer execute only when a button is pressed.
bindEvent( x, ..., ignoreNULL = TRUE, ignoreInit = FALSE, once = FALSE, label = NULL )
x | An object to wrap so that is triggered only when a the specified event occurs. |
---|---|
... | One or more expressions that represents the event; this can be a
simple reactive value like |
ignoreNULL | Whether the action should be triggered (or value
calculated) when the input is |
ignoreInit | If |
once | Used only for observers. Whether this |
label | A label for the observer or reactive, useful for debugging. |
Shiny's reactive programming framework is primarily designed for calculated
values (reactive expressions) and side-effect-causing actions (observers)
that respond to any of their inputs changing. That's often what is
desired in Shiny apps, but not always: sometimes you want to wait for a
specific action to be taken from the user, like clicking an
actionButton()
, before calculating an expression or taking an action. A
reactive value or expression that is used to trigger other calculations in
this way is called an event.
These situations demand a more imperative, "event handling" style of
programming that is possible--but not particularly intuitive--using the
reactive programming primitives observe()
and isolate()
. bindEvent()
provides a straightforward API for event handling that wraps observe
and
isolate
.
The ...
arguments are captured as expressions and combined into an
event expression. When this event expression is invalidated (when its
upstream reactive inputs change), that is an event, and it will cause
the original object's code to execute.
Use bindEvent()
with observe()
whenever you want to perform an action
in response to an event. (Note that "recalculate a value" does not
generally count as performing an action -- use reactive()
for that.) The
first argument is observer whose code should be executed whenever the event
occurs.
Use bindEvent()
with reactive()
to create a calculated value that only
updates in response to an event. This is just like a normal reactive expression except it ignores all the usual invalidations that
come from its reactive dependencies; it only invalidates in response to the
given event.
bindEvent()
is often used with bindCache()
.
bindEvent()
takes an ignoreNULL
parameter that affects behavior when
the event expression evaluates to NULL
(or in the special case of an
actionButton()
, 0
). In these cases, if ignoreNULL
is TRUE
, then it
will raise a silent validation error. This is useful behavior
if you don't want to do the action or calculation when your app first
starts, but wait for the user to initiate the action first (like a "Submit"
button); whereas ignoreNULL=FALSE
is desirable if you want to initially
perform the action/calculation and just let the user re-initiate it (like a
"Recalculate" button).
bindEvent()
also takes an ignoreInit
argument. By default, reactive
expressions and observers will run on the first reactive flush after they
are created (except if, at that moment, the event expression evaluates to
NULL
and ignoreNULL
is TRUE
). But when responding to a click of an
action button, it may often be useful to set ignoreInit
to TRUE
. For
example, if you're setting up an observer to respond to a dynamically
created button, then ignoreInit = TRUE
will guarantee that the action
will only be triggered when the button is actually clicked, instead of also
being triggered when it is created/initialized. Similarly, if you're
setting up a reactive that responds to a dynamically created button used to
refresh some data (which is then returned by that reactive
), then you
should use reactive(...) %>% bindEvent(..., ignoreInit = TRUE)
if you
want to let the user decide if/when they want to refresh the data (since,
depending on the app, this may be a computationally expensive operation).
Even though ignoreNULL
and ignoreInit
can be used for similar purposes
they are independent from one another. Here's the result of combining
these:
ignoreNULL = TRUE
and ignoreInit = FALSE
This is the default. This combination means that reactive/observer code
will run every time that event expression is not
NULL
. If, at the time of creation, the event expression happens
to not be NULL
, then the code runs.
ignoreNULL = FALSE
and ignoreInit = FALSE
This combination means that reactive/observer code will run every time no matter what.
ignoreNULL = FALSE
and ignoreInit = TRUE
This combination means that reactive/observer code will
not run at the time of creation (because ignoreInit = TRUE
),
but it will run every other time.
ignoreNULL = TRUE
and ignoreInit = TRUE
This combination means that reactive/observer code will
not at the time of creation (because ignoreInit = TRUE
).
After that, the reactive/observer code will run every time that
the event expression is not NULL
.
bindEvent()
can be used with reactive expressions, observers, and shiny
render functions.
When bindEvent()
is used with reactive()
, it creates a new reactive
expression object.
When bindEvent()
is used with observe()
, it alters the observer in
place. It can only be used with observers which have not yet executed.
In many cases, it makes sense to use bindEvent()
along with
bindCache()
, because they each can reduce the amount of work done on the
server. For example, you could have sliderInputs x
and y
and a
reactive()
that performs a time-consuming operation with those values.
Using bindCache()
can speed things up, especially if there are multiple
users. But it might make sense to also not do the computation until the
user sets both x
and y
, and then clicks on an actionButton named
go
.
To use both caching and events, the object should first be passed to
bindCache()
, then bindEvent()
. For example:
r <- reactive({ Sys.sleep(2) # Pretend this is an expensive computation input$x * input$y }) %>% bindCache(input$x, input$y) %>% bindEvent(input$go)
Anything that consumes r()
will take a reactive dependency on the event
expression given to bindEvent()
, and not the cache key expression given to
bindCache()
. In this case, it is just input$go
.