Trying to display an HTML file in Anvil, how to do it?

What I’m trying to do:
I am trying to display HTML file in Anvil GUI, using the Image element, with GOOGLE COLAB editor
Code Sample:
I am passing the HTML file to the Anvil editor like so - GOOGLE COLAB side:
import anvil.media
@anvil.server.callable
def run_func():
media = anvil.media.from_file(HTML_FILE)

In the Anvil editor I am trying to use:

def image_2_show(self, **event_args):
“”“This method is called when the Image is shown on the screen”“”
html_file = anvil.server.call(‘run_func’)
self.image_2.source = html_file

Welcome to the Forum!

An image is a picture, in .png, .svg, etc. format. You’re probably looking for HTML Forms.

Hi,
Thanks for the quick replay.

That is not exectaly what I was looking for, as my HTML is uniqe and actually is a special GEEMAP file wrapped in HTML.
Maybe it is simpler to just display geemap.eefolium.Map object? if so, how it can be done?

What errors did you get when you tried using a custom HTML form with your GEEMAP generated HTML? You might need to check the browser development console for Javascript related errors.

1 Like

I didn’t get any error.
It just didn’t display anything.
Black screen.
This is the code I have used:
< In Colab>

import anvil.media
@anvil.server.callable
def run_australia():
#Create a Media object from the exported image
HTML = anvil.media.from_file(HTML_FILE_PATH)

< Anvil side>

def drop_down_1_change(self, **event_args):
“”“This method is called when an item is selected”“”
country = self.drop_down_1.selected_value
if country == ‘Australia’ :
HTML_file = anvil.server.call(‘run_australia’)
#Create an iframe element and set the src
#Set the source property of the Iframe component to the HTML string
#iframe = jQuery(“<iframe width='100%'height=‘800px’>”).attr(“src”,HTML_file)# This line is in comment only for the forum display, apperntly it drives this page nuts :slight_smile:
iframe.appendTo(get_dom_node(self.column_panel_2))

That’s not using custom HTML forms, that’s using an iframe. An iframe is intended to link to another web page via a URL, not embed HTML directly into it (unless your HTML is formatted for that specific purpose).

You’re also using a media file where a string is expected. They’re not interchangeable.

Your server function doesn’t actually return a value, so it would be None.

My advice would be to simplify everything. You’re dealing with an HTML file which is just text. Read it in as a string and return that string from your server function.

In your form code, use a custom HTML form (see Phil’s link from above) and set its html property to the string the server function returns.

See what happens, and report back. The above may or may not work, largely depending on what’s in the HTML string. If it’s a full HTML page then it may not play well with Anvil’s HTML. If it’s just a portion of a page, then it should be fine.

Hi
Thanks for the help.
To make things more precise what I am trying to do is to disaply a MAP with HTML as someone mentioned here, but it doesn’t seems to be solved yet.

Any idea how to do it?
(Seems like something very basic…)

Did you already work through the approach I suggested above? That’s how I would try it. If that doesn’t work, post back here with what went wrong.

I did what you mentioned like so:
Colab side:


@anvil.server.callable
def get_map_html():
  #Use .get_root().render() to render the map to HTML.
  html_string = m43.get_root().render()
  return html_string

In the Anvil side:

class Form1(Form1Template):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    # Add a ColumnPanel to your form
    self.column_panel = ColumnPanel()
    self.add_component(self.column_panel)

    # Create an HtmlPanel component
    self.map_html_panel = HtmlPanel()
    self.map_html_panel.width = "100%"  # Adjust width as needed
    self.map_html_panel.height = "500px"  # Adjust height as needed
    #self.add_component(self.map_html_panel)
    # Add the HtmlPanel to the ColumnPanel
    self.column_panel.add_component(self.map_html_panel)


  def drop_down_1_change(self, **event_args):
    """This method is called when an item is selected"""
    country = self.drop_down_1.selected_value
    if country == 'Australia' :
          
          
          self.map_html_panel.content = anvil.server.call('get_map_html')
          # Add the HtmlPanel to the ColumnPanel
         
          # Add the HtmlPanel to the form
          #self.add_component(self.map_html_panel)
          #self.map_webview.set_html(map_html)
          pass  
    
    pass

No error appears, but nothing is shown when I select the relevant country.

I’m not sure exactly what HTMLPanel is, but if it’s a custom HTML form then you would need to set its .html property. You’re setting the .content property instead, which isn’t a thing for custom HTML forms as far as I know.

Here’s an example of creating an HTML component dynamically and assigning HTML to it that might help (it saves you needing a separate blank custom HTML form):

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    self.html_component = HtmlTemplate()
    self.content_panel.add_component(self.html_component)
    
  def button_1_click(self, **event_args):
    self.html_component.html = self.text_area_1.text
1 Like

Running the code you provided I see a blank screen and nothing appear on it. What I should have seen running this code?
( I assume a button? )

Did you just copy the code as is? That wasn’t the point. The code showed the technique of creating an html component and setting the .html property. You need to incorporate that into your non-working code.

If you did incorporate the technique I showed in your code, you’ll have to show that code for me to offer any advice on why it isn’t working.

I tried to integrate it but it still didn’t work.
First let me say that I appriciate your help on this :slight_smile:
And it helps me to understand better how to work with this tool.
Second,
in order to make things even more simpler let’s just say that I want to display this:
m = folium.Map(location=[45.5236, -122.6750], zoom_start=13)
Here is my Colab side:
m = folium.Map(location=[45.5236, -122.6750], zoom_start=13)
@anvil.server.callable
def get_map_html():
html_string = m.get_root().render()
return html_string

Is that correct in the Colab side? and what is the simple thing to write in Anvil side in order to see it?

Assuming that what gets returned is an HTML string, yes. Presumably you can print that out and verify that you’re getting the right results.

Do note what I mentioned above:

To display it on Anvil, go back to what you were trying to do:

and read my comment on what’s wrong with that:

and if that isn’t clear look at the example I posted:

Unless I’m missing something, you’ve got all the information you need to display any HTML string your server function returns. Whether that HTML plays well with Anvil’s existing HTML/CSS is another issue, but you won’t know that until you get the above working.

Something did show up, but still I get bunch of errors. Here is the code I tried in the Anvil side:

class Form1(Form1Template):
  def __init__(self, **properties):
    self.init_components(**properties)
    self.html_component = HtmlTemplate()
    self.add_component(self.html_component)

  def drop_down_1_change(self, **event_args):
    """This method is called when an item is selected"""
    country = self.drop_down_1.selected_value
    if country == 'Australia' :
          # Add the HtmlPanel to the ColumnPanel
          self.html_component.html = anvil.server.call('get_map_html')
          )
          pass  
    pass

btw using this line:
self.content_panel.add_component(self.html_component)
creates a blank screen

What errors? What showed up?

  • [An internal error has occurred] - see browser console for more details

  • global code@https://tceovki53hcbeldx.anvil.app/debug/53WSWMICOHB4DIVY7XKUFZYQPNQDPDXA%3DTSZKOFUVJXT5OCJT22WH77PG/_/debug:4:57 appendChild@[native code] b@https://anvil.works/runtime-new/runtime/node_modules/jquery/dist/jquery.min.js:2:850 Pe@https://anvil.works/runtime-new/runtime/node_modules/jquery/dist/jquery.min.js:2:48537 @https://anvil.works/runtime-new/runtime/node_modules/jquery/dist/jquery.min.js:2:50985 $@https://anvil.works/runtime-new/runtime/node_modules/jquery/dist/jquery.min.js:2:32396 set@https://anvil.works/runtime-new/runtime/dist/runner.bundle.js:578:399 setProp@https://anvil.works/runtime-new/runtime/dist/runner.bundle.js:28:64264 tp$call@[native code] @https://anvil.works/runtime-new/runtime/js/lib/skulpt.min.js:206:67 $drop_down_1_change891$@ @ q@https://anvil.works/runtime-new/runtime/js/lib/skulpt.min.js:424:318 m@https://anvil.works/runtime-new/runtime/js/lib/skulpt.min.js:424:373

  • [An internal error has occurred] - see browser console for more details

  • Script error.

Looks like something didn’t like the HTML that was set. Was the error list you posted from the browser console? It looks pretty generic to me (basically saying it crashed when the HTML was set).

The way you’re displaying the HTML looks fine. You should be able to test that workflow by returning simpler HTML from your server function (a paragraph with some bold text, for example).

If that simpler HTML works, then the issue is with the mapping HTML. As a test, can you save the HTML you get back from the server as a .html file and open it in a browser to make sure the HTML works outside of the Anvil environment?

I did the following:
with open(‘/content/drive/MyDrive/try/map.html’, ‘w’) as f:
f.write(html_string)

Works perfectly and open as expected in a web browser.

The error I wrote earlier was copied from the Anvil console:
“Running App Console”

Ah, when an Anvil message says to check the browser console, it means to check the Javascript console on the browser. That internal error means something happened in Javascript that Anvil doesn’t know how to handle, and it’s suggesting you investigate there.

Every browser has a different method to open the browser console. Look up how to do it in your browser, then run the app to generate the error (when running in the IDE, run the app in a new tab rather than embedded in the IDE). The browser console should display a bunch of messages. Some of those will be the error that triggered the Anvil error. That can sometimes give a clue as to what’s going wrong.

Likely, though, there won’t be anything you can do to fix it, since you don’t control the generated HTML.

There’s another approach to embedding HTML in an Anvil app that’s more complicated, but should avoid the issues of incompatible HTML. It goes back to the iframe technique you originally tried.

  1. Write an HTTP endpoint that calls the server function and returns the HTML. Anvil Docs | Creating HTTP APIs

  2. In the form, have an iframe whose source is the address of that HTTP endpoint

Your map HTML is now basically in a page all its own, displayed by the iframe. It should be outside of the Anvil environment, so shouldn’t conflict with Anvil’s HTML.