-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdynamic_modules.Rmd
144 lines (121 loc) · 3.71 KB
/
dynamic_modules.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
---
title: "Dynamically adding and removing Shiny modules"
author: "Jonas Hagenberg"
institute: "Appsilon Shiny Conference"
date: "27.04.2022"
output:
xaringan::moon_reader:
css: xaringan-themer.css
lib_dir: libs
nature:
highlightStyle: github
highlightLines: true
countIncrementalSlides: false
ratio: "16:9"
---
```{r setup, include=FALSE}
options(htmltools.dir.version = FALSE)
```
```{r xaringan-themer, include=FALSE, warning=FALSE}
library(xaringanthemer)
style_duo_accent(
primary_color = "#1a5f96",
secondary_color = "#03A696",
code_inline_background_color = "#f8f8f8"
)
```
# Code availability
Find the code on github:
https://github.com/jonas-hag/dynamic_shiny_modules
---
# Dynamic modules
- modules are either called when initialising the Shiny app or dynamically
--
- dynamic modules can be useful when:
- something has to be repeated based on user input
- e.g. show several plots or tables
- a set of UI elements
--
- can become complex easily -> use it with care!
???
- set of UI elements: e.g. additional layers in plots that can be controlled
- how to get from static modules to dynamically added modules? -> livecoding
---
# Selectors
- used in `jQuery`, the JavaScript framework used by Shiny
- based on CSS selectors
- can select e.g. element types
- for us relevant: select elements by `id`
---
# Adding modules
When adding a module:
- call the module `server` function
- insert the module UI elements with `insertUI`
- use an appropriate `selector` where to insert the UI - one can use an empty `div`
with an `id`
- use a different `id` for every added module instance
---
# How to remove a module
- remove UI part with `removeUI`
- needs to provide a selector
- works well for one UI element but not for several in module UI
- wrap UI elements with `div` with module `id` instead of `tagList`
```{r, eval = FALSE}
module_UI <- function(id) {
ns <- NS(id)
div( #<<
id = id,
# your UI elements here
)
}
```
???
- the selector is based on the id of the UI elements
- in our case the id of the module
---
# Recap: remove UI of a module
- use `removeUI`
- create a selector with `#` and the module `id`
- use a unique `id` for every module
???
- this removes the contents of the module on the client side
---
# How to remove the server part
- so far, only UI elements were removed
- `input`s, `reactive`s and `observeEvent`s of the module are still in
the server part
- can negatively influence the performance
- therefore also remove these
---
# Remove `input`s
- `input`s are still stored on the serve side and consume memory
--
```{r, eval = FALSE}
remove_shiny_inputs <- function(id, .input) {
invisible(
lapply(grep(id, names(.input), value = TRUE), function(i) {
.subset2(.input, "impl")$.values$remove(i) #<<
})
)
}
```
By [Thomas Roh](https://roh.engineering/posts/2020/02/shiny-add/removing-modules-dynamically/), CC BY-NC 4.0
???
- pass the `id` of the module that should be removed (`id`), the different inputs
are matched automatically
- pass the list (here: `input`) where the inputs are stored
- for every module input, call the `remove` method
- rather hacky method, not Shiny official
- currently don't know a way to remove `reactive` expressions
---
# Destroy `observeEvent`s
- you can also destroy `observeEvent`s from removed modules
- please check out the additional information section of the repository
- check out the [Appsilon Blog Post](https://appsilon.com/how-to-safely-remove-a-dynamic-shiny-module/)
---
# Summary
- use `insertUI`/`removeUI` for the module UI
- remove inputs and destroy `observeEvent`s to clean up the server side and
avoid performance issues
- use unique `id`s to avoid problems
- use dynamic addition/removal only sparingly