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

insertUI/callModule to add, removeUI/??? to remove (no mechanism to deactivate a "server" instance) #2281

Open
avsdev-cw opened this issue Dec 7, 2018 · 6 comments

Comments

@avsdev-cw
Copy link

avsdev-cw commented Dec 7, 2018

This would probably also solve #1797 #548 and #2040

In short, there is capability to a) modularise application server processing (by using callModule) and there is also b) capability to add/remove UI sections via a number of mechanisms, but commonly via insertUI/removeUI.

When trying to use a combination of the above we encountered the problem that there seems to be no opposite to callModule().

For example:

  • Imagine you have a data set and you wish to allow your users have a widget to select an X axis column, a Y axis column and plot it - as part of a larger application you would write a sub-module/widget that would allow them to do that which would consist of select box for X, a select box for Y and a plot output.
  • Now extend that concept by allowing users to create multiple instances of the widget (ie a dashboard of graphs) - this could be achieved by using insertUI([target], [after], [UI of widget - with ID]) and calling callModule([ID of UI of widget], [data]). This would produce a UI/Server pair which hangs off the session namespace via id ID (having used ns <- NS(id) and ns("selectX") etc).
  • Finally, you want to provide the ability for your users to remove graphs as they want. The UI element can be removed with removeUI(), but there is no capacity (that I know of) to remove the server functionality added with callModule()

Arguably, as long as the UI/Server pair has a unique ID every time, this is workable with the cost of non-release of memory and processing of removed widgets. However, if you take the same principle and use it to serve tabs on your site which would have the same ID each time they are instantiated/selected then currently you end up with multiple server instances reacting to a single UI instance that is regenerated each time the user moves away from and back to - all due to the fact that there is no way to do the reverse of callModule() [that I know of]

NOTE: this is specifically a problem when using output$plot <- ...., observe({ input$selectX }) or observeEvent(input$selectY, {}) in the sub-module/widget

@AshesITR
Copy link

Would a work-around be to (manually) keep a list of active modules?

modules <- list(id1 = module_fun_1, id2_a = module_fun_2, id2_b = module_fun_2)
purrr::iwalk(modules, function(fun, id, ...) callModule(id, fun, ...))

registering a new module or overwriting an existing one would be done with

modules$id2_c <<- module_fun_2 # or NULL

@avsdev-cw
Copy link
Author

avsdev-cw commented Dec 11, 2018

In short, no.

There seem to be quite a few complexities around the inner workings of the server side of the modules, especially around reactive values, (not forgetting outputs that are triggered by them!), the session (and session environment) itself and the use of observeEvent/observe.

For example, when you use observeEvent/observe within the modules, there are references made elsewhere (ie registering the observe as a callback in a stack somewhere - guess?) which keep the GC from cleaning them (at least, that's what I am again guessing). Arguably the solution to this particular part might be to retain a list of all observers that the module makes and the $suspend or $destroy them manually - and recurse through the module tree into deeper modules too, (doesn't solve what to do with the session object though)

@pat-alt
Copy link

pat-alt commented Nov 29, 2019

Have there been any developments on this issue? Thanks

@earnaud
Copy link

earnaud commented Aug 4, 2020

I used to store observers in a reactiveValues and on removal, destroy them with their methods. But as these methods are not documented, this is quite a blind way to do and absolutely not a "good practice", just a trick.

@avsdev-cw
Copy link
Author

@earnaud That is essentially what I've ended up having to do (I use a list instead of a reactiveValues though). It works when there are only a few observe's that you are doing, but when you start writing complex apps with 50+ observes it's very easy to miss one.

Is there still no progress on this from Shiny devs?

@anirbanshaw24
Copy link

Instead of removing each observer separately, we could remove the moduleServer() itself:

all_reactive_values[[ns("my_module-server")]] <-
    moduleServer(id, function(input, output, session) { ...

# Then remove server with
all_reactive_values[[ns("my_module-server")]]$destroy()

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

5 participants