Trying to pull the same boilerplate html file into all my apps

I am slowly developing a very simple set of shiny apps. I have been putting the same text into all my apps which gives people some context, in each app, about the whole set and how the shiny relates to other things I'm doing. I have been putting that in the sidebar but I'd rather put it at the bottom of my mainPanel. What I really want to be able to do is to pull the text from a single file so that I can update it regularly and not have to change every app. So far you can see my failed attempt to achieve this at: https://shiny.psyctc.org/apps/RCI1/. You will see the current boilerplate text in the sidebar and you can see my abortive attempt to recreate it using a text file in the root of the shiny server. That is being pulled into the mainPanel as you can see but it is (of course) in the highlight colour as I have used renderPrint() to create it and you can see that the HTML is not being parsed as HTML (as I'm using renderPrint()!). The code of the app is in apps/RCI1 at GitHub - cpsyctc/shiny-server: My git/github repository for my shiny server (I think it's public so can be pulled).

I think one way to do this is through templates (https://shiny.posit.co/r/articles/build/templates/) but that seems to be talking about templates created in the app directory while I want to use a template ideally in the root of the server. I see that it is possible in principle to put a template into a package and I do have a package (https://cecpfuns.psyctc.org/) so I guess I could try to go that way but I can't help thinking that someone else will have already solved this challenge and can show me how to do this more simply! TIA, Chris

I have worked out a solution to my problem. I think it's ugly but it works.
I put the template I want into the root of my shiny server, I called it boilerplate.html. For what it's worth, my current file is this:

<!-- boilerplate.html -->
<div>
  <h3><center>Background and related resources</center></h3>
  This shiny app is one of a growing number in, <a href="https://shiny.psyctc.org/">my shiny server</a><br>
  They complement:
  <ul>
    <li><a href="href = https://www.psyctc.org/Rblog/index.html">my Rblog</a> of posts about using R</li>
    <li><a href="https://www.psyctc.org/psyctc/book/glossary/">the glossary</a> linked with</li>
    <li><a href="href = https://www.psyctc.org/psyctc/book/">the OMbook</a></li>
    <li>and it's all part of the resources of <a href="https://www.psyctc.org/psyctc/">PSYCTC.org</a></li>
    <li>and linked with <a href="https://www.coresystemtrust.org.uk">the CORE system web site</a></li>
  </ul>
  <p>There is a form if you want to <a href="https://www.psyctc.org/psyctc/contact-me/">contact me</a>: so do please use that if you think there is anything wrong here or anything that could be improved.<br>
  <p>There is also now an Email announcement list, never updating more than monthly, where I will put up developments of new apps here, a summary of updates to the glossary and new posts in the Rblog. You can sign up for that <a href="https://ombook.psyctc.org/signup">here</a>.
</div>

Then I create a one line bash script to copy that to all the subdirectories of apps:

find apps -maxdepth 1 -type d -exec cp boilerplate.txt {} \;

Then I can then pull that template file into each of me apps by adding this:

htmlTemplate("boilerplate.html")

at the bottom of mainPanel() in the app.

It works. Now I will tweak my existing apps to use that and in future I can update boilerplate.html when I want/need to, run the bash one liner and all the apps get their own copies of the template updated.

A couple of footnotes to this:

{% raw %}
<!-- component.html -->
<div>
  This is an HTML template named <code>{{ name }}</code>.
</div>
{% endraw %}

as an example of a template component. I found that if I included the {% raw %} and {% endraw %} they were included verbatim into my app output so I deleted them and it still works.

  • I think some cacheing in my Rstudio (2023.06.1 Build 524 on Ubuntu 22.04.2) means that if I change the template file in the app directly and reload the app (or stop and restart it), a cached copy of the template before my changes gets used still. I have solved this by coming out of Rstudio and restarting it but I'm sure there must be a better way around this.

First, the point of a template is that you can create a template file once, and reuse it multiple times changing some variable in it. You don't actually use that functionality, as you're always including the exact same html. So in your context you can simply includeHTML() your boilerplate text.

Another problem is that your find command works well enough once, but if you ever start modifying the text then you have to make sure you keep all copies synchronized, it's going to be a huge pain. What would be better is to maintain a single version of the boilerplate at a single place, and make sure all other pages can link to it.

The nice thing about includeHTML() is that it takes a path as argument, that can be a physical path on your hard drive or an URL to a file hosted online. So let's say you put your boilerplate text in a file and make it available at the URL "shiny.psyctc.org/boilerplate.html", then you can just add a link to it in each of your apps, if you modify the central location it will change in all apps automatically (neglecting cache issues, you can always use ctrl + shift + R or similar to force your browser to reload everything).

An example similar to what you want (using the example minimal app in ?sidebarLayout):

library(shiny)

ui <- fluidPage(
  
  # main content
  titlePanel("Example page"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("obs",
                  "Number of observations:",
                  min = 0,
                  max = 1000,
                  value = 500)
    ),
    mainPanel(
      plotOutput("distPlot")
    )
  ),
  
  # footer
  hr(),
  tags$footer(
    includeHTML("https://shiny.psyctc.org/boilerplate.html")
  )
)

server <- function(input, output) {
  output$distPlot <- renderPlot({
    hist(rnorm(input$obs))
  })
}

shinyApp(ui, server)

Note that you don't have to use tags$footer(), you can use a simple div() or other if you prefer.

Thanks AlexisW. As long as I remembered to run the find after changing the referential boilerplate.html there would be no pain, that's what that one liner was for.

However, your solution is clearly cleaner. Rather weirdly I thought I had tried pretty much that and got an error which I clearly misinterpreted. I'm not sure that I have the energy to change things now as what I have works as I'm up to 11 apps now so it's a fair amount of editing yet again!

Minor grump about shiny: I really find the documentation tends to assume that you know far more than I do as a beginner with it. The pages about templates could start simply by saying something like:
"If you want to include a simple block of HTML into some or all your apps you can use includeHTML() but if you want a standard block of HTML that includes a variable templates are what you need. One difference from includeHTML() is that it is easier to reference the same block of HTML across several apps using includeHTML() than with htmlTemplate() which expects the template to be in the app directory. There are ways around this using packages, see below, but includeHTML() is better for a block of HTML with no embedded variables."
I don't think the classical help structure of base R functions is perfect and I guess what I'm saying is partly saying that the help for includeHTML() and htmlTemplate() in htmltools could have done a bit more to crossreference the two functions. OK, probably tiredness speaking but we all get tired and miss things sometimes? Any comment on the {% raw %} and cacheing issues? The latter certainly baffled me for a bit yesterday! Anyway, thanks for educating me and taking the time to explain it well.

I was tired and grumpy. includeHTML() clearly much cleaner so I did do all the edits! Thanks again AlexisW.

Haha no problem. Indeed if you don't use the template capabilities I think it's cleaner to go with the simpler version.

I'm not familiar with templating, my guess is there must be a subtle typo/parameter to set somewhere; if you did care about it we could try rerunning the examples and your code to find the problem, but here it's not really necessary.

I (partly) agree: I feel the Mastering Shiny book is really good for the R/Shiny point of view, but as soon as you go into more customizations (writing html, css, or javascript yourself) there are still good resources, but scattered everywhere on the web, and it's hard to figure out what you need. And you often need a good knowledge of web technologies just to realize it may exist.

This topic was automatically closed 54 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.