-
Notifications
You must be signed in to change notification settings - Fork 0
/
shinyjs-example.Rmd
267 lines (205 loc) · 6.69 KB
/
shinyjs-example.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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
---
title: "shinyjs example app walk-through"
author: "Dean Attali"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{shinyjs example app walk-through}
%\VignetteEngine{knitr::rmarkdown}
%\usepackage[utf8]{inputenc}
---
```{r setup, echo = FALSE, message = FALSE}
knitr::opts_chunk$set(tidy = FALSE, comment = "#>")
```
# shinyjs example app walk-through
This document provides a step-by-step guide on how to add a variety of shinyjs features to a simple app in order to make it more user friendly.
*You can view the final Shiny app developed in this simple example
[here](http://daattali.com/shiny/shinyjs-basic/).*
Suppose we want to have a simple Shiny app that collects a user's basic
information (name, age, company) and submits it, along with the time of
submission. Here is a very simple implementation of such an app (nothing
actually happens when the user "submits").
```
library(shiny)
shinyApp(
ui = fluidPage(
div(id = "myapp",
h2("shinyjs demo"),
textInput("name", "Name", ""),
numericInput("age", "Age", 30),
textInput("company", "Company", ""),
p("Timestamp: ", span(date())),
actionButton("submit", "Submit")
)
),
server = function(input, output) {
}
)
```
*Note that I generally don't like running Shiny apps like this and prefer to
declare the UI and server separately, but this style is used here for brevity.*
Here is what that app would look like
![Demo app](../inst/img/demo-basic-v1.png)
### Add shinyjs features
Now suppose we want to add a few features to the app to make it a bit more
user-friendly. First we need to set up the app to use `shinyjs` by making a call to `useShinyjs()` in the Shiny app's UI.
Here are 7 features we'll add to the app, each followed with the code to
implement it using `shinyjs`:
**1. The "Name" field is mandatory and thus the "Submit" button should not be
enabled if there is no name**
In the server portion, add the following code
```
observe({
if (is.null(input$name) || input$name == "") {
shinyjs::disable("submit")
} else {
shinyjs::enable("submit")
}
})
```
Or instead you can use the `toggleState` function and pass it a `condition`:
```
observe({
shinyjs::toggleState("submit", !is.null(input$name) && input$name != "")
})
```
You can use the optional `condition` in some other functions as well, which
can be very useful to make your code shorter and more understandable.
**2. The "Age" and "Company" fields are optional and we want to have the ability
to hide that section of the form**
First, we need to section off the "Age" and "Company" elements into their own
section, so we surround them with a `div`
```
div(id = "advanced",
numericInput("age", "Age", 30),
textInput("company", "Company", "")
)
```
We also need to add a link in the UI that will be used to hide/show the section
```
a(id = "toggleAdvanced", "Show/hide advanced info")
```
Lastly, we need to tell Shiny to show/hide the section when the link is clicked
by adding this code to the server
```
shinyjs::onclick("toggleAdvanced",
shinyjs::toggle(id = "advanced", anim = TRUE))
```
**3. Similarly, since we don't really care about "Age" and "Company" too much, we
want to hide them initially when the form loads**
Simply surround the section we want to hide initially with `shinyjs::hidden`
```
shinyjs::hidden(
div(id = "advanced",
...
))
```
**4. The user should be able to update the "Timestamp" in case he spends way too
long filling out the form (not very realistic here, and the timestamp should
ideally be determined when the button is clicked, but it's good enough for
illustration purposes)**
First, we need to add an "Update" link to click on, and we need to give the
element showing the time an `id` so that we can refer to it later when we
want to change its contents.
To do that, replace `p("Timestamp: ", span(date()))` with
```
p("Timestamp: ", span(id = "time", date()), a(id = "update", "Update"))
```
Now we need to tell Shiny what to do when "Update" is clicked by adding this
to the server
```
shinyjs::onclick("update", shinyjs::html("time", date()))
```
**5. Some users may find it hard to read the small text in the app, so there should
be an option to increase the font size**
First, we need to add checkbox to the UI
```
checkboxInput("big", "Bigger text", FALSE)
```
In order to make the text bigger, we will use CSS. So let's add an appropriate
CSS rule by adding this code to the UI
```
shinyjs::inlineCSS(list(.big = "font-size: 2em"))
```
Lastly, we want the text to be big or small depending on whether the checkbox
is checked by adding this code to the server
```
observe({
if (input$big) {
shinyjs::addClass("myapp", "big")
} else {
shinyjs::removeClass("myapp", "big")
}
})
```
Or, again, we can use the `toggleClass` function with the `condition` argument:
```
observe({
shinyjs::toggleClass("myapp", "big", input$big)
})
```
**6. Give the user a "Thank you" message upon submission**
Simply add the following to the server
```
observeEvent(input$submit, {
shinyjs::alert("Thank you!")
})
```
**7. Allow the user to reset the form**
First let's add a button to the UI
```
actionButton("reset", "Reset form")
```
And when the button is clicked, reset the form
```
observeEvent(input$reset, {
shinyjs::reset("myapp")
})
```
### Final code
The final code looks like this
```
library(shiny)
shinyApp(
ui = fluidPage(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(list(.big = "font-size: 2em")),
div(id = "myapp",
h2("shinyjs demo"),
checkboxInput("big", "Bigger text", FALSE),
textInput("name", "Name", ""),
a(id = "toggleAdvanced", "Show/hide advanced info", href = "#"),
shinyjs::hidden(
div(id = "advanced",
numericInput("age", "Age", 30),
textInput("company", "Company", "")
)
),
p("Timestamp: ",
span(id = "time", date()),
a(id = "update", "Update", href = "#")
),
actionButton("submit", "Submit"),
actionButton("reset", "Reset form")
)
),
server = function(input, output) {
observe({
shinyjs::toggleState("submit", !is.null(input$name) && input$name != "")
})
shinyjs::onclick("toggleAdvanced",
shinyjs::toggle(id = "advanced", anim = TRUE))
shinyjs::onclick("update", shinyjs::html("time", date()))
observe({
shinyjs::toggleClass("myapp", "big", input$big)
})
observeEvent(input$submit, {
shinyjs::alert("Thank you!")
})
observeEvent(input$reset, {
shinyjs::reset("myapp")
})
}
)
```
You can view the final app [here](http://daattali.com/shiny/shinyjs-basic/).