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 …