Select specific component with javascript

So I spent quite a lot of time working on how to do this with the popover and hover/focus behaviour dependencies…

This was my methodology and how I came about it:

  • call the js function from the init method of a Form or from a button click or wherever makes sense…

  • use the component as an argument

  • if we then take a look at the component with console.log(component) we can start to dive into its attributes and methods using chrome dev tools.

  • the path of the html element is: component.v._anvil.element (note this is a jQuery object)

  • (depending on the component you will get different html tags - so a link component gives the <a> tag, text_box gives you the input element, a button component gives the surrounding div)

Optional:

  • if you wanted to send the same element back to python use component.v e.g. anvil.call(html_element, 'my_function', component.v)

Example below:

https://anvil.works/build#clone:SIXH2YXISGCZN3VS=KWOC3UBMEFM243P27RS7UEZU

The code in the example is:

js.call_js('make_component_red', self.label_2)
js.call_js('make_component_red', self.button_1)
js.call_js('make_component_red', self.link_1)

in Native Libraries
<script>

function make_component_red(component){
    var html_element = component.v._anvil.element // jQuery Object
    html_element.css('background','red')

    // optional - if you want to then send this element back to a python function
    anvil.call(html_element, 'i_am_red', component.v)
};
  
</script>

A method inside the HTML Form that the component belongs to…(i.e. not a Blank Panel Form)

  def i_am_red(self, component):
    print(f"component '{component.__name__}' is now red")



side note: since the html element of a button component: button_component.v._anvil.element is the div rather than the button element, I got into the habit of using:

if (component.v._anvil.element[0].classList.contains("anvil-button")) {
        var html_component = $(component.v._anvil.element[0].firstElementChild) 
        // jQuery Button object rather than the surrounding div
    }
else { var html_component = component.v._anvil.element}; // jQuery object

But I don’t think it’s really necessary for most use cases…

You could also do:

if (component.v._anvil.componentSpec.type == "Button") {
        var html_component = $(component.v._anvil.element[0].firstElementChild)
        // jQuery Button object rather than the surrounding div
    }
else { var html_component = component.v._anvil.element}; // jQuery object

which is prettier… But only anvil elements that are created in the designer have a js attribute componentSpec.
Elements that are created in code don’t seem to have a componentSpec attribute so the former code worked more generally… I found this out the hard way…




side side note - I’m sure this is a case of use with caution - it’s not documented and just the result of me hacking around - anything not documented might be liable to change - but then again - the popover dependency made it into the component library

4 Likes