@@ -703,6 +703,10 @@ execCount <- function(x) {
703
703
704
704
# Observer ------------------------------------------------------------------
705
705
706
+ # The initial value of "current observer" is NULL (and will always be NULL,
707
+ # except when within the scope of the observe or observeEvent)
708
+ .globals $ currentObserver <- NULL
709
+
706
710
Observer <- R6Class(
707
711
' Observer' ,
708
712
portable = FALSE ,
@@ -814,6 +818,8 @@ registerDebugHook("observerFunc", environment(), label)
814
818
run = function () {
815
819
ctx <- .createContext()
816
820
.execCount <<- .execCount + 1L
821
+ .globals $ currentObserver <- self
822
+ on.exit(.globals $ currentObserver <- NULL ) # On exit, set it back to NULL
817
823
ctx $ run(.func )
818
824
},
819
825
onInvalidate = function (callback ) {
@@ -904,6 +910,125 @@ registerDebugHook("observerFunc", environment(), label)
904
910
)
905
911
)
906
912
913
+ # ' Return the current observer
914
+ # '
915
+ # ' This function is useful when you want to access an observer's methods or
916
+ # ' variables directly. For example, you may have logic that destroys or
917
+ # ' suspends the observer (from within its own scope) on some condition.
918
+ # '
919
+ # ' This function works by returning the observer that is currently being run
920
+ # ' when \code{getCurrentObserver()} is called. If there is no observer being
921
+ # ' run (for example, if you called it from outside of a reactive context),
922
+ # ' it will always return \code{NULL}. There are a few subtleties, however.
923
+ # ' Consider the following five situations:
924
+ # '
925
+ # ' \enumerate{
926
+ # ' \item \code{getCurrentObserver() #outside of a reactive context}
927
+ # ' \item \code{observe({ getCurrentObserver() }) }
928
+ # ' \item \code{observe({ (function(){ getCurrentObserver() })() )} }
929
+ # ' \item \code{observe({ isolate({ getCurrentObserver() }) }) }
930
+ # ' \item \code{observe({ reactive({ getCurrentObserver() }) }) }
931
+ # ' }
932
+ # '
933
+ # ' In (1), since you're outside of a reactive context, we've already
934
+ # ' established that \code{getCurrentObserver()} will return \code{NULL}.
935
+ # ' In (2), we have the "vanilla" case, in which \code{getCurrentObserver()}
936
+ # ' is called directly from within the body of the \code{observe} call.
937
+ # ' This returns that observer. So far, so good. The problem comes with
938
+ # ' the last three cases -- should we be able to "retrieve" the outer
939
+ # ' observer if we're inside an inner function's scope, or inside of an
940
+ # ' \code{isolate} or a \code{reactive} block?
941
+ # '
942
+ # ' Before we can even asnwer that, there is an important distinction to
943
+ # ' be made here: are function calls, \code{reactive} calls and
944
+ # ' \code{isolate} blocks the same \emph{type} of thing? As far as Shiny
945
+ # ' is concerned, the answer is no. Shiny-specific things (like observers,
946
+ # ' reactives and code inside of an \code{isolate} chunk) exist in what we
947
+ # ' call reactive contexts. Each run of an observer or a reactive is
948
+ # ' associated with a particular reactive context. But regular functions
949
+ # ' have no relation to reactive contexts. So, while calling a regular
950
+ # ' function inside of an observer does not change the reactive context,
951
+ # ' calling a \code{reactive} or \code{isolate} certainly does.
952
+ # '
953
+ # ' With this distinction in mind, we can refine our definition of
954
+ # ' \code{getCurrentObserver()} as follows: it returns the observer (if any)
955
+ # ' that is currently running, as long as it is called from within the
956
+ # ' same reactive context that was created when the observer started
957
+ # ' running. If the reactive context changed (most likely because of a
958
+ # ' call to \code{reactive} or \code{isolate}), \code{getCurrentObserver}
959
+ # ' will return \code{NULL}. (There is another common way that the reactive
960
+ # ' context can change inside an observer, which is if there is a second,
961
+ # ' nested observer. In this case, \code{getCurrentObserver()} will return
962
+ # ' the second, nested observer, since that is the one that is actually
963
+ # ' running at that time.)
964
+ # '
965
+ # ' So to recap, here's the return value for each of the five situations:
966
+ # ' \enumerate{
967
+ # ' \item \code{NULL}
968
+ # ' \item the observer
969
+ # ' \item the observer
970
+ # ' \item \code{NULL}
971
+ # ' \item \code{NULL}
972
+ # ' }
973
+ # '
974
+ # ' Now, you may be wondering why \code{getCurrentObserver()} should't be able
975
+ # ' to get the running observer even if the reactive context changes. This isn't
976
+ # ' technically impossible. In fact, if you want this behavior for some reason,
977
+ # ' you can set the argument \code{dig} to be \code{TRUE}, so that the function
978
+ # ' will "dig" through the reactive contexts until it retrieves the one for the
979
+ # ' observer and returns the observer.
980
+ # '
981
+ # ' So, with \code{dig = TRUE}, here's the return value for each of the five
982
+ # ' situations:
983
+ # ' \enumerate{
984
+ # ' \item \code{NULL}
985
+ # ' \item the observer
986
+ # ' \item the observer
987
+ # ' \item the observer
988
+ # ' \item the observer
989
+ # ' }
990
+ # '
991
+ # ' The reason that this is not the default (or even encouraged) is because
992
+ # ' things can get messy quickly when you cross reactive contexts at will.
993
+ # ' For example, the return value of a \code{reactive} call is cached and that
994
+ # ' reactive is not re-run unless its reactive dependencies change. If that
995
+ # ' reactive has a call to \code{getCurrentObserver()}, this can produce
996
+ # ' undesirable and unintuitive results.
997
+ # '
998
+ # ' @param dig If \code{FALSE} (default), \code{getCurrentObserver} will only
999
+ # ' return the observer if it's invoked directly from within the observer's
1000
+ # ' body or from a regular function. If \code{TRUE}, it will always return
1001
+ # ' the observer (if it exists on the stack), even if it's invoked from
1002
+ # ' within a \code{reactive} or an \code{isolate} scope. See below for more
1003
+ # ' information.
1004
+ # '
1005
+ # ' @return The observer (created with a call to either \code{observe} or to
1006
+ # ' \code{observeEvent}) that is currently running.
1007
+ # '
1008
+ # ' @seealso \code{\link{observe}}
1009
+ # '
1010
+ # ' @examples
1011
+ # ' ## Only run examples in interactive R sessions
1012
+ # ' if (interactive()) {
1013
+ # ' shinyApp(
1014
+ # ' ui = basicPage( actionButton("go", "Go")),
1015
+ # ' server = function(input, output, session) {
1016
+ # ' observeEvent(input$go, {
1017
+ # ' print(paste("This will only be printed once; all",
1018
+ # ' "subsequent button clicks won't do anything"))
1019
+ # ' getCurrentObserver()$destroy()
1020
+ # ' })
1021
+ # ' }
1022
+ # ' )
1023
+ # ' }
1024
+ # ' @export
1025
+ getCurrentObserver <- function (dig = FALSE ) {
1026
+ o <- .globals $ currentObserver
1027
+ ctx <- getCurrentContext()
1028
+ if (! dig && ! is.null(o ) && ctx $ id != o $ .ctx $ id ) o <- NULL
1029
+ o
1030
+ }
1031
+
907
1032
# ' Create a reactive observer
908
1033
# '
909
1034
# ' Creates an observer from the given expression.
0 commit comments