learnr
learnr copied to clipboard
Horizontal layout option for `question_radio()`
Motivation:
Pedagogically, it can sometimes be useful to provide a long list of distractors. It's also helpful to be able to ask many short questions. Regrettably, the question options in {learnr}
lay things out in a vertical format. The result is visually confusing.
Proposal:
I propose a layout option like this:
Actually, I'd prefer if the submit/try-again buttons were inline with the question prompt, to save further vertical space.
I'm implemented the above via an inline
field passed via the general-purpose options=
argument. Then a very small change in radio_question.R
will provide the option while preserving the default behavior ...
question_ui_initialize.learnr_radio <- function(question, value, ...) {
choice_names <- answer_labels(question)
choice_values <- answer_values(question)
radioButtons(
question$ids$answer,
label = question$question,
inline = ifelse("inline" %in% names(question$options),
question$options$inline,
FALSE),
choiceNames = choice_names,
choiceValues = choice_values,
selected = value %||% FALSE # setting to NULL, selects the first item
)
}
To get the question type, try defining this in one of your setup
chunks...
question_ui_initialize.learnr_radio_inline <- function(question, value, ...) {
choice_names <- answer_labels(question)
choice_values <- answer_values(question)
radioButtons(
question$ids$answer,
label = question$question,
inline = TRUE,
choiceNames = choice_names,
choiceValues = choice_values,
selected = value %||% FALSE # setting to NULL, selects the first item
)
}
Then in your exercise chunk... (See Custom Question Types)
question(...., type = c("learnr_radio_inline", "learnr_radio"))
This will not solve the inline try again/submit button, but it should get you half way.
I don't know of a best solution for having the submit
/try again
button being inline. Don't know if it should be a question()
option or an S3 method for the layout.
Ex:
-
question(inline = FALSE, question_inline = inline, answer_inline = inline)
-
question_ui_layout.default <- ....
This is a big help. Thanks, Barret @schloerke. For others trying to use this technique, please note that ...
-
answer_labels()
is not exported by{learnr}
, so be sure to qualify it aslearnr:::answer_labels
- the
%||%
expression used in theselected =
argument is also an unexported helper from{learnr}
. The definition is"%||%" <- function(x, y) if (is.null(x)) y else x
- you will also need to implement the required method
question_is_correct
, which you can do with
question_is_correct.learnr_radio_inline <- learnr:::question_is_correct.learnr_radio
I have tried this and it worked - however, the answer is still printed vertically. Can this be changed?
With the help of @dtkaplan and @schloerke I managed to get the wanted behaviour:
answer_labels <- learnr:::answer_labels
answer_values <- learnr:::answer_values
"%||%" <- function(x, y) if (is.null(x)) y else x
question_is_correct.learnr_radio_inline <- learnr:::question_is_correct.learnr_radio
question_ui_initialize.learnr_radio_inline <- function(question, value, ...) {
choice_names <- answer_labels(question)
choice_values <- answer_values(question)
radioButtons(
question$ids$answer,
label = question$question,
inline = TRUE,
choiceNames = choice_names,
choiceValues = choice_values,
selected = value %||% FALSE # setting to NULL, selects the first item
)
}
question_ui_completed.learnr_radio_inline <- function (question, value, ...) {
choice_values <- learnr:::answer_values(question)
choice_names_final <- lapply(question$answers, function(ans) {
if (ans$correct) {
tag <- " ✓ "
tagClass <- "correct"
}
else {
tag <- " ✗ "
tagClass <- "incorrect"
}
tags$span(ans$label, HTML(tag), class = tagClass)
})
learnr:::disable_all_tags(radioButtons(question$ids$answer, label = question$question,
choiceValues = choice_values, choiceNames = choice_names_final,
selected = value, inline = TRUE))
}
Below I have made a radio_q
function just to avoid repeating the input in the questions. If you just need to insert an inline question just follow @schloerke's question(...., type = c("learnr_radio_inline", "learnr_radio"))
advice
radio_q <- function(inline = FALSE){
question(type = c("learnr_radio_inline", "learnr_radio")[c(inline, TRUE)],
text = "Which package contains functions for installing other R packages?",
answer("base [N]"),
answer("tools [N]"),
answer("utils [Y]", correct = TRUE),
answer("codetools [N]")
)
}
quiz(radio_q(), radio_q(TRUE))