As a reminder, the namespace is an important aspect of shiny module that prevents collision of input and output IDs in your application. The namespace identify each unique instance of the modules and need to be provided by the caller.
tidymodules can be considered as an object-oriented organisational layer on top of shiny that does conventional module in the background. It does use namespace but make it optional to the users. In other words, you don’t need to remember it!
In the example below a tm module MyMod
is
defined and called with the new()
function and with no
arguments supplied.
Printing the instance m
to the console shows the structure
of the module.
library(tidymodules)
#> Loading required package: shiny
MyMod <- R6::R6Class(
"MyMod",
inherit = TidyModule
)
m <- MyMod$new()
m
#> Module Namespace MyMod-1
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
The namespace Id for module m
above is
MyMod-1
. It is a unique Id generated by
tidymodules and composed of the class name and the
initialisation order of the module.
The user can also provide a more informative name when initialising a module.
m <- MyMod$new("Tom")
m
#> Module Namespace Tom
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
Tom
end up being the namespace Id of m
.
The provided name must begin with a letter [A-Za-z]
and
may be followed by any number of letters, digits [0-9]
,
hyphens -
, underscores _
. You should not use
the following characters as they have a special meaning on the UI ( CSS
/ jQuery ).
~ ! @ $ % ^ & * ( ) + = , . / ’ ; : ” ? > < [ ] { } | ` #
The code below illustrates a very simple example of nested module and the corresponding namespace Ids. Here are few things to note about this example:
ModA
and ModB
are both tm
classes as they both inherit from
tidymodules::TidyModule
ModB
is used as a nested class of
ModA
ModA
has a public field named
nested_mod
ModB <- R6::R6Class(
"ModB",
inherit = TidyModule
)
ModA <- R6::R6Class(
"ModA",
inherit = TidyModule,
public = list(
nested_mod = NULL,
initialize = function(...) {
super$initialize(...)
self$nested_mod <- ModB$new()
}
)
)
m <- ModA$new()
n <- m$nested_mod
m
#> Module Namespace ModA-3
#> Module Session global_session
#> - Class ModA << TidyModule << R6
#> - Input [0]
#> - Output [0]
n
#> Module Namespace ModA-3-ModB-4
#> Module Session global_session
#> - Class ModB << TidyModule << R6
#> - Input [0]
#> - Output [0]
This option allows the grouping of tm modules together
to facilitate their retrieval from the ModStore
and to
better visualize them later in a network diagram.
ta <- MyMod$new("Tom", group = "A")
tb <- MyMod$new("Tom", group = "B")
ta
#> Module Namespace A-Tom
#> Module Group A
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
tb
#> Module Namespace B-Tom
#> Module Group B
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
As you can see above the group argument is used to define the final namespace Id of the modules. Those modules share the same name but have different namespace IDs.
A tm module namespace is a concatenation of many fields.
name
and
group
id
,
parent_ns
and module_ns
the module’s namespace is built like this
id = <group>_<name>
module_ns = <parent_ns>_<id>
#' @field name Name of the module, either generated for or provided by the user.
n$name
#> [1] "ModB-4"
ta$name
#> [1] "Tom"
#' @field group Group name of the module.
n$group
#> NULL
ta$group
#> [1] "A"
#' @field id ID of the module.
n$id
#> [1] "ModB-4"
ta$id
#> [1] "A-Tom"
#' @field parent_ns Parent module namespace in case of nested modules.
n$parent_ns
#> [1] "ModA-3"
ta$parent_ns
#> NULL
#' @field module_ns Module namespace, unique identifier for the module.
n$module_ns
#> [1] "ModA-3-ModB-4"
ta$module_ns
#> [1] "A-Tom"
Like in conventional module, tm module also requires
wrapping UI elements with the namespace. The function named
ns()
available in all tm modules should be
used to namespace the inputs. As you can see in the example below, you
simply need to call the function using the self
R6 keyword.
There is no need to remember the modules’s namespace anymore.
MyMod <- R6::R6Class(
"MyMod",
inherit = TidyModule,
public = list(
ui = function() {
shiny::tagList(
shiny::numericInput(self$ns("inputId"), NULL, 0)
)
}
)
)
m <- MyMod$new()
as.character(m$ui())
#> [1] "<div class=\"form-group shiny-input-container\">\n <label class=\"control-label shiny-label-null\" for=\"MyMod-7-inputId\" id=\"MyMod-7-inputId-label\"></label>\n <input id=\"MyMod-7-inputId\" type=\"number\" class=\"shiny-input-number form-control\" value=\"0\"/>\n</div>"
ModStore
and module lookup
The ModStore
is an internal repository for all
tm modules and connections (see communication article for learning how to
connect modules). It is a shared environment created by
tidymodules that orginizes the objects (modules and
edges) by applications and sessions. This allows to track and easily
retrieve the modules anywhere in the application.
All the examples above show the creation of modules with the
new()
R6 function and the assignment to variables (pointers
to the R6 objects). However tidymodules also offers the
choice to not save module references and instead use the
getMod()
or mod()
utility functions to
retrieve existing module. Note that mod()
is just an alias
of getMod()
.
MyMod$new("SaveMeInStore")
#> Module Namespace SaveMeInStore
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
# look-up by namespace ID
mod("SaveMeInStore")
#> Module Namespace SaveMeInStore
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
# look-up by index
mod(2)
#> Module Namespace Tom
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]
# look-up by index within a group
mod(1, group = "A")
#> Module Namespace A-Tom
#> Module Group A
#> Module Session global_session
#> - Class MyMod << TidyModule << R6
#> - Input [0]
#> - Output [0]