How to get properties from an Anvil compontent in JS?

I’m trying to get the width of a simple Anvil card component and log it within Javascript. Due to lack of JS knowledge I am unable to get it working.

As a minimalistic example I created a custom form with two card components, each with a different width in px, because the 2nd card is contained within the 1st card. Both cards also contain an custom html component which use <script> tags. Within those script tags I’m trying to get the width of the cards they are contained in. Alternatively, it would also satisfy to alert properties like width of any component like a card (rather than the component in which the custom html form is contained).

<script>
  // alert('test') js works
  alert() // here I would like to alert the width of the Anvil card component in which the HTMl component is contained.
</script>

You may want to read through the docs about the Javascript bridge. The docs spread it over a few pages, but this one details how to drive Javascript from Python: Anvil Docs | Accessing JavaScript

The vast majority of what I see people trying to do in Javascript can be done equally well in Python, using the Javascript bridge, without every writing Javascript. You don’t give any details on the context of why you’re trying to do what you’re trying to do, so we can’t offer any advice on using the Javascript bridge to do it.

I can say that what your clone is doing (running code when an HTML page is loaded) is almost certainly not what you want to do. That code will run well before the Form is fully instantiated, and so there won’t be any card components to get the width of.

More context on the problem you’re trying to solve would be helpful.

1 Like

Thanks for the info, it’s good to now that the html code is executed before the Python code is executed.

What I’m actually trying to achieve is as follows, there is a chart library in JS for which I need to set the width responsively, so it works on desktop, mobile, etc.

var chart = LightweightCharts.createChart(document.getElementById("chart"), { width: x, height: y,      
          });

Isn’t it possible to call a JS function within Anvil after the card is initiated? It should be possible to resize the chart after it gets initiated:

function resize() {
    chart.applyOptions({ width: x, height: y })
}

The form’s form_show event is the typical place to run code after the visual components have initialized. In there you’d use the Javascript bridge to set the width of your chart. You’d want to create the chart and keep a reference to it in the form, so you can later interact with it.

Here’s some relevant sample code from a project where I integrated the CodeMirror Javascript library to use their editor:

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

    def form_show(self, **event_args):
        from anvil.js.window import CodeMirror

        config = {
          'lineNumbers': True,
          'toolBar': True,
          'mode': {
            'name': 'python',
            'singleLineStringErrors ': True,
            'version': 3
          },
          'configureMouse': lambda a,b,c: {'addNew' : False},
          'indentUnit': 4,
          'indentWithTabs': True,
          'gutters': ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
          'foldGutter': True,
        }

        self.cm_editor = CodeMirror(js.window.document.getElementById('editor'), config)
        self.cm_editor.on('changes', self.changed)
        self.cm_editor.setSize(None, 500)
        self.cm_editor.getWrapperElement().addEventListener('keydown', self.cm_keydown)

This shows importing and creating the Javascript element, along with setting up a callback to a Python function, and setting up a Javascript event listener, all from Python.

1 Like

Alright, in the meantime I managed to find another solution directly in JS but it’s still a very useful example and good to know for the future, thanks!

The trick that made it work in plain JS was as follows, place the chart in another div and then use:

    // make the y-axis show on mobile
    chart.applyOptions({ 
        width: chartDiv.offsetWidth, 
        height: chartDiv.offsetHeight 
      });

    // make the chart responsive, so when window reszies, the y-axis stays
    window.onresize = function() {
      chart.applyOptions({ 
        width: chartDiv.offsetWidth, 
        height: chartDiv.offsetHeight 
      });
    }