-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathnamespace.Rmd
212 lines (140 loc) · 5.43 KB
/
namespace.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
---
pagetitle: "Namespace management"
title: "Namespace management"
subtitle: "<div style='float:right;'><i style='color:#285fa4;' class='fas fa-th-large fa-4x'></i></div>"
author: "Mustapha Larbaoui"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Namespace management}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
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!
## Optional namespace Id
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.
```{r, eval=TRUE}
library(tidymodules)
MyMod <- R6::R6Class(
"MyMod",
inherit = TidyModule
)
m <- MyMod$new()
m
```
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.
## User defined namespace Id
The user can also provide a more informative name when initialising a module.
```{r, eval=TRUE}
m <- MyMod$new("Tom")
m
```
`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 ).
> ~ ! @ $ % ^ & * ( ) + = , . / ' ; : " ? > < [ ] \ { } | ` #
## Namespace and nested modules
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`
* The namespace of a nested module is always prefixed with its parent
```{r, eval=TRUE}
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
n
```
## Grouping modules
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.
```{r, eval=TRUE}
ta <- MyMod$new("Tom", group = "A")
tb <- MyMod$new("Tom", group = "B")
ta
tb
```
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.
## module's IDs and UI function
A `{tm}` module namespace is a concatenation of many fields.
* Some are optional fields: `name` and `group`
* And some are managed by `{tidymodules}`: `id`, `parent_ns` and `module_ns`
the module's namespace is built like this
```
id = <group>_<name>
module_ns = <parent_ns>_<id>
```
```{r,eval=TRUE}
#' @field name Name of the module, either generated for or provided by the user.
n$name
ta$name
#' @field group Group name of the module.
n$group
ta$group
#' @field id ID of the module.
n$id
ta$id
#' @field parent_ns Parent module namespace in case of nested modules.
n$parent_ns
ta$parent_ns
#' @field module_ns Module namespace, unique identifier for the module.
n$module_ns
ta$module_ns
```
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.
```{r,eval=TRUE}
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())
```
## `ModStore` and module lookup
The `ModStore` is an internal repository for all `{tm}` modules and connections (see [communication article](communication.html) 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()`.
```{r,eval=TRUE}
MyMod$new("SaveMeInStore")
# look-up by namespace ID
mod("SaveMeInStore")
# look-up by index
mod(2)
# look-up by index within a group
mod(1, group = "A")
```