You have a bookdown book with exercises and
solutions to those exercises. You would like to control visibility of
the solutions. For example, when the bookdown file loads, you would
like all the solutions to be hidden. You would like a button for each
solution to toggle its visibility. How to do this? We faced this
problem when preparing materials for our CVXR
tutorial.
A little Javascript can easily solve this problem.
Example
We will use the minimal book that comes with Rstudio when you create a
new bookdown project as an example. Go ahead and edit the file
01-intro.Rmd
adding the following two exercises towards the end.
We first create a header.html
file to include some Javascript in the
main directory (the same directory containing 01-intro.Rmd
) with the
following contents, which I’ve intentionally made verbose for
legibility.
<script>
$(document).ready(function () {
process_solutions();
});
function process_solutions() {
$("div.section[id^='solution']").each(function(i) {
var soln_wrapper_id = "cvxr_ex_" + i;
var solution_id = $(this).attr('id');
var button = $("<button onclick=\"toggle_solution('" + soln_wrapper_id + "')\">Show/Hide</button>");
var new_div = $("<div id='" + soln_wrapper_id + "' class='solution' style='display: none;'></div>");
var h = $(this).first();
var others = $(this).children().slice(1);
$(others).each(function() {
$(this).appendTo($(new_div));
});
$(button).insertAfter($(h));
$(new_div).insertAfter($(button));
})
}
function toggle_solution(el_id) {
$("#" + el_id).toggle();
}
</script>
The functions above use jquery
API calls. When the document is
loaded in a browser, the process_solutions
call will modify the DOM
tree to hide the solutions. First it locates all the solution sections
and for each such section does the following.
- Generates an id (
soln_wrapper_id
) which will be used for a newly createddiv
element (new_div
) with no visibility by default; - Creates a button element with text
Show/Hide
to toggle display of any element specified by an id (el_id
); - Locates the first header section in the solution (
h
) and the rest of the elements that follow the header (others
); - Moves the
others
intonew_div
; - Inserts the button after the header;
- Finally, moves the
new_div
after the button (button
).
To include this header file, we need to modify _output.yml
to
include the lines below in the bookdown::gitbook
section, at the
right level of indentation (that of css
, config
).
includes:
in_header: header.html
Try it
My source for this example is in my github repo.
If you now preview the book, you will see something like this where you can toggle the solutions on and off.
Extensions
If the book is served from a host controlled by the instructor, I would think it possible to have solutions toggled on and off by the instructor for student viewing. I would think that the Rstudio folks would be able to make such a thing work with their RStudio Connect product.