Search code examples
javascriptdjango

Django app: how to read a bit of HTML in JavaScript


I have a Django app that has a design issue I'd like to fix: a script wants to inject a piece of HTML that contain Django tags.

What we have now works is:

  • Save the script as an HTML snippet that is nothing but a script: the first line is <script> and the last line closes that script.
  • This script sets a local variable to a hard-coded string containing the HTML to inject.

So the snippet an HTML file that contains nothing but a script, and that script in turn contains the HTML to inject as a hard-coded string. This is confusing to read and prevents our JavaScript and HTML linters from working on this snippet.

Is there a cleaner solution? I want to store the JavaScript in a .js file and, preferably, the HTML to inject in a .html file.

I have tried the following, none of which work, and none which meet all of these goals:

1: Change the HTML snippet to a static JavaScript file, while retaining the hard-coded HTML string inside. This fails, because the Django tags are not replaced (no surprise) and in any case the JavaScript still contains hard-coded HTML.

2: Use the DOM to get at the HTML to inject, as follows:

  • Move the script to a static js file.
  • Move the HTML to inject to a new HTML snippet, putting it in a hidden containing div with a unique id.
  • The script gets the HTML string by using the DOM to get the containing div, and calling innerHTML.
  • The script then uses the DOM to remove the containing div (once I have the string), so it won't interfere with other code.

This breaks unit tests. And indeed it seems risky to add unwanted HTML to a page.

I could change the hidden added HTML so that it could not interfere (i.e. pick new names and then modify them in the script) but that seems ugly and error-prone. I could also generate the HTML piece by piece in the JavaScript, but that adds a lot of code.

Any ideas for a cleaner solution? I tried lots of web searching, but suspect I am not asking the question right.


Solution

  • I took Abdul Aziz Barkat's excellent advice and changed my containing <div id=...> to a <template id=...> and everything started working. I obtain the html string by getting the innerHTML of the template element, and there's no need to try to remove any elements from the page.

    I also changed the html snippet to load the associated static javascript file, so the html that uses the scripts can just import the snippet.

    Note: do not set the shadowrootmode property of the <template> for this use case. That broke things for me (regardless of whether I set it to "open" or "closed") and it's not needed.