Text formatting using html in label component

Hello,

I am trying to display some text in a label. The text to be displayed comes in from another function and depending on various conditions, different aspects of the text needs to be coloured/formatted differently…so I am trying to use hmtl to achieve this.

I have looked at a few examples in the forum and tried out a couple of things, mainly following this link:
https://anvil.works/forum/t/display-text-in-various-formats-in-the-same-component/795/7

and cloned this app as well:

However I am getting this error:

[An internal error has occurred]

NameError: Could not find global JS function ‘updateText’.

updateText is the name of the function that has been described in the asset file new_file.html and I dragged this as a component onto my main form:

<script>
  function updateText(match){
    <html>
      <head></head>
 		<body>
           <p>some text<br>
            <br><br><h2>{match}</h2><br>
            some more text<br>
           </p>
        </body>
    </html>
  }
</script>

Another thing I tried was to set the item property of the html file (used as a component) to a python variable like so:

> html = """\
>       <html>
>         <head></head>
>         <body>
>            <p>some text<br>
>             <br><br><h2>{match}</h2><br>
>             some more text<br>
>            </p>
>         </body>
>       </html>
>       """.format(match=match)

This does not spew out errors, however nothing shows up in the hmtl component either.

Please help.

1 Like

Hello @i.rajeshwari
the clone link you posted doesn’t look a valid clone link.
Please could you post a clone link to your APP?
That would help to clarify the context and the error.

BR

Hi there,

Here’s an app demonstrating what I’m trying to do and the errors.
https://anvil.works/build#clone:5DUEU6LJV64NLHP7=WXVMCI6USLKPVY245CRIDWWO

Thanks for your help!

Hi @i.rajeshwari
Approach 1
the internal error is due to the code in your Javascript function.

<script>
  function updateText(match){
<html>
        <head></head>
        <body>
           <p>You got 1 concept of the answer right.<br>
            <br><br><h2>{match}</h2><br>
            Look at the model answer to evaluate what you missed.<br>
           </p>
        </body>
      </html>
  }
</script>

This is not Javascript code, you can’t put HTML inside a Javascript function.
You could assign that HTML to a variable and print it out like this:

<script>
    function updateText(match){
      let my_html = `<html>
                      <head></head>
                      <body>
                      <p>You got 1 concept of the answer right.<br>
                      <br><br><h2>{match}</h2><br>
                      Look at the model answer to evaluate what you missed.<br>
                        </p>
                        </body>
                        </html>`;
      document.write(my_html);
      }
</script>

But that would replace the whole document (that is, the whole app).
I don’t think this is what you want. This is what Approach1 button does now.

Approach 2
What does not work here is that you’re updating the wrong attribute.
It’s not self.custom_1.item = html but self.custom_1.html = html.
You don’t need all the page-level html, like <html><head> and <body>.
See Approach 3 code, your html could be as short as:

    html = """
           <p>You got 1 concept of the answer right.<br>
            <br><br><h2>{match}</h2><br>
            Look at the model answer to evaluate what you missed.<br>
      """.format(match=match)

Approach 4 is what I think you were trying to obtain with your initial Javascript function.
How it works:

  • you have the custom html component with the standard html code. The only trick is that the element h2, whose text you’re going to change via Javascript, is identified by an ID, “my_text” in this case
<html>
  <head></head>
  <body>
    <p>You got 1 concept of the answer right.<br>
      <br><br><h2 id="my_text">{match}</h2><br>
    Look at the model answer to evaluate what you missed.<br>
  </body>
</html>

Again, you don’t need the <html><head> and <body> tags since you’re injecting this HTML code inside the ANVIL built page.

  • Javascript function updateText2 just changes H2’s text:
  function updateText2(match) {
    let element = document.getElementById("my_text");
    element.textContent = match;
  }
  • Python code just shows the custom component (it is made hidden in the init method, this is why all the buttons now set it visible again) and calls this Javascript function updateText2

Interesting to note is that if you click button Approach 4 after Approach 2 or 3, then ANVIL will throw an error Cannot set property 'textContent' of null. Instead, if you click it just after having run the app, it works. This makes perfectly sense. This is because the buttons Approach 2 and 3 will replace the custom component’s HTML with theirs own HTML code, which lacks the id="my_text" attribute. So the updateText2 tries to set the attribute of an element it can’t find anymore, and throws the error.

See the code here:

https://anvil.works/build#clone:OE2Z2PWCTKTRWX3V=VIPPMRJCMK5S5YAZR45SYQN6

BR

1 Like

Wow - thank you so much for all that explanation! I gave up and ended up using multiple labels for all the bits of text I wanted to display!!

But I am going to give this approach a try this week and update. Really appreciate your help on this!

Once again, thank you so much for your help. Just what I was looking to achieve!

1 Like