The ultimate goal of htmltools is to *manipulate*, *combine* and *rearrange*
tags in order to create flexible and rich HTML structures from R. Would you
believe that the below example heavily relies on htmltools (Figure 2.1)?
htmltools provides the necessary functions to write HTML tags that were
introduced in Chapter 1.3. In R, it is even more convenient than raw HTML
since there is no opening/closing tag, a simple function call instead:
Inside the function call, all named elements become *attributes*, whereas
unnamed elements become *children*. In some cases, tags may have empty
attributes like . In that case,the corresponding R code is input(disabled =
NA).
Pro tip: Since tag functions produce Shiny tags, that is, HTML elements,
calling tag inside a document will render the tag instead of printing its
code. Sometimes, particularly in this book, you want to see the code
output. In that case, use the code below.You may find another example here.
When building custom templates, you will be writing a lot of tags. It might
seemtoo much work to always write tags$. There exists a function called
withTags(), which allows you to get rid of all tags$. Hence, the whole code
is much easier to write and read:
The first has the shiny.tag.list class in addition to list. You may see it
as a detail, but this has noticeable consequences. For instance, tag_list_1
prints as HTML content, whereas tag_list_2 prints as a list. If we try to
apply as.character() on both elements, we obtain very different outputs:
Good practice is to check whether the created tag is in line with the HTML
validation rules. If you want to check a web page, particularly a
Shiny-generated HTML page, W3C has an online validation tool. Be careful,
as not following this rule will cause the HTML code to be invalid. By
default, Shiny complies with all the recommendations, but we suggest you be
careful with any exotic template.
htmltools comes with the HTML() function that you can feed with raw HTML.
It prevents HTML escaping on the provided content, which is convenient, for
instance, when using formatting tags inside a string:
Interestingly, if you want to convert raw HTML to R code, there is a Shiny
App developed by AlanDipert from RStudio, namely html2R, shown Figure 2.3.
Non-standard attributes (like data-toggle) are not correctly processed, but
there are solutions. This will save you precious time! A more recent
approach is developed in Chapter 21 and has been used internally to develop
some of the RinteRface templates.
Below we give concrete example on how to customize tags in real life. There
exists anice RPG HTML template, that is, rpgui. It providesthe necessary
elements to get started developing nice RPG-looking user interfaces, as
depicted by Figure 2.4.
In the following, we consider the select input, which does not have exactly
the samestructure as the original Shiny tag. However, it is convenient to
reuse the Shiny functionsto limit our amount of work. We therefore start to
write our custom input:
To fix the first problem we target the outer tag (selectTag), that is, the
tag returned by our rpgSelect() function. The second row cleans the label
class. The third row removes the extra outer div and only keeps its
children, corresponding to the input tag. The last instruction ensures we
set the appropriate class, depending on the size value:
These are two lines of code, and believe me, for complex examples, it might
be much worse, thereby significantly impairing code
readability.Fortunately, htmltools provides powerful functions to overcome
this issue, the most significant being reviewed below.
As you may notice, the first approach may lead to *poorly* written code as
soon as thetag structure gets more complex. You may easily end up with
things like tag$children[[1]]$children[[2]]$children[[1]]$attribs$class,
which is nearly impossible to maintain.The second approach is much more
human *readable*, even though not necessarily shorter in this example.The
biggest advantage is that is does not always depend on the overall tag
structure. As an exercise, you may wrap the span elements inside another
div parent:
Another reason to prefer the new tagQuery() API is the substantial
performance gains. Interestingly, under the hood, most if not all older
htmltools functions like tagAppendChildren() or tagAppendAttributes() call
the tagQuery() API when .cssSelector is provided. In practice,while we can
achieve multiple modifications at once with a single tagQuery() call, it
requires a combination of multiple
tagAppendChildren()/tagAppendAttributes() to reach the same result, thereby
leading to less performance.Are you ready to become a tag witcher
[^tag-witcher]?
As shown in the preliminary example, the main interest of querying tags is
to ultimately modify them. tagQuery() exposes methods to modify *attributes*,
*children* of the query selection.
You may think it will add each text to the corresponding panel item, but
methods like $append() and $prepend() are only able to add the same
element(s) to one or multiple target(s). It will actually add three new
children to each selected panel. For this case where the content is *index*
specific, we have to utilize $each(). It takes an anonymous function as
input, with two parameters. x is the tag and i is the current index. Inside
that function, you may edit the tag depending on the index and return the
modified structure:
Then we create our custom tag with the .renderHook parameter available for
the htmltools tag element, providing a special function, namely a *render
hook*, that will be called upon for tag rendering:
In practice, you will rarely have only one render hook to handle. Most
Shiny elements are composedof main wrappers and *nested* tags. For
instance, nav elements like tabsetPanel() and tabPanel() are, again, the
perfect example.
The next step is to design the nested item function. The tag consists of
asimple div element with a class. In the render hook, we get the theme
versionand, depending on the result, we add a child to the item with
$append().Note the new-child class. This is the one targeted one level up
in my_wrapper_tag().
It is basically a resolve issue. In the top-level render hook, the newly
added item is not yet available. To check this, we can put a browser() just
before the tagQuery() flow inside my_wrapper_tag():
install.packages("htmltools")
Error in install.packages : Updating loaded packages
install.packages("htmltools")
WARNING: Rtools is required to build R packages but is not currently
installed. Please download and install the appropriate version of Rtools
before proceeding:
The presence of the path containing 00LOCK is likely a problem. Try
uninstalling htmltools. If that (allegedly) succeeds, check to make sure
the 00LOCK path no longer exists. If it persists, try deleting it. Once
00LOCK is gone, try installing htmltools again.
Thanks, but in the packages list, htmltools doesn't appear. Is there
another way to uninstall it? Also, RTools doesn't appear, but was in
another complaint, and I am unable to install it.
UPDATE: Part of the problem appears to be that I need to run RStudio as
Administrator.
Are you saying that if (in RStudio) you click on the Packages tab, then
click the Install button, then (with the Install from: box set to
Repository (CRAN)) type htmltools in the Packages box, it is not listed?
I would suggest shutting down RStudio and restarting it (without loading
any scripts or documents) before attempting to install or update any
packages, to reduce the likelihood that the package you are updating is
already active in memory.
Did you install RTools? Note that RTools is not an R library; it's a
separate program, which is apparently need to compile the source code for R
libraries. (I'm on Linux, where the tool chain for compiling libraries is
already installed.) So you don't install it within RStudio; you download
the exe file from the site you linked, run it to install RTools, and then
try installing/updating R libraries.
OK, decided to uninstall.reinstall R, to get the 4.3 level. Then downloaded
and installed RTools. Then ran RStudio as Admin, and again tried to update
rlang, which again failed, again complaining that RTools is not installed.
Surely there must be steps which will walk me through this. I am ready to
uninstall the whole chain and start over. My confidence in RStudio updates
has plummeted.
*UPDATE:* The short answer, the one that actually solves the problem, is
this:
I'm trying to open a new R Markdown document in the RStudio IDE, but it
keeps giving me the following message: "Creating R Markdown documents
requires updated versions of the following packages: htmltools, rmarkdown.
Do you want to install these packages now?"
You opted for the "later source version," it looks like. There's seldom a
need to do that and it introduces additional opportunity for trouble. The
binary version will have necessarily sorted the compile time dependencies.
Try that.
@fgootkind, be aware there are other package repository alternatives that
provide precompiled binaries for some Linux distributions. I'm aware of two
mainstream options, the public Posit Package Manager and r2u (for the last
two Ubuntu LTS releases only) and one option for ARM architectures, the
R4Pi Project (currently only for Raspberry Pi OS).
This topic was automatically closed 45 days after the last reply. New
replies are no longer allowed.
If you have a query related to it or one of the replies, start a new topic
and refer back with a link.
The problem is that since you are using an old R version the latest
precompiled binary of htmltools available for it is too old and you don't
have RTools properly installed to compile htmltools from source.
This topic was automatically closed 42 days after the last reply. New
replies are no longer allowed.
If you have a query related to it or one of the replies, start a new topic
and refer back with a link.
--
You received this message because you are subscribed to the Google Groups
"beets" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/beets-users/620ac172-2f6f-4d87-8d82-1bb36805fcafn%40googlegroups.com.