Javascript anvil.call DOM element - self.call_js vs anvil.js.call_js

My app structure is as follows:
MainForm --> component-panel --> ComponentForm --> component-panel --> multiple componenets each of which is SubForm containing a textArea.

I want to change the behaviour of the Enter Key for the textareas.

I think I’m close but I don’t understand how to correctly select the SubForm as the DOM element argument in anvil.call

on the ComponentForm show event I have:

anvil.js.call_js('set_enter_behaviour') 

in the native library, I have a function that sets the keydown behaviour for the enter key.

function enter_behaviour(e){
  	if(e.which==13){
      e.preventDefault()
      linkElement = this
      anvil.call(this,'textarea_pressed_enter')
    };
};
  
function set_enter_behaviour() {
    $('textarea').on('keydown',enter_behaviour);
  };
  

The error I get is as follows

Exception: Attempted to call non-existent method from Javascript: <MainForm object> has no attribute 'textarea_pressed_enter'.
at <template>, line <unknown>

So it seems that this is the MainForm, whereas I want this to be the correct SubForm that the textarea is contained within. Help…

Minimal Example below:
https://anvil.works/build#clone:JWVPDALD2KRRT3PG=2AGB6OSUQBOTVDFKX6YZRUGU

@stucork

Ok …

I have rejigged the paradigm. Take a look at “SubForm2”

https://anvil.works/build#clone:OLF7NRJ45R43HK7P=XSIMC5I46S2M3VBAFEN36WQW

I have pushed the enter trap code into a self contained function in the custom HTML code for the text area form. Each one should act independently.

See if it makes sense. If not, I’ll try and explain it later.

edit just updated it to assign a random id to each instance so you can tell which textarea is getting the event. Note the JS is not the best - I am an amateur at it - and it can probably be simplified/bettered by someone on here, but it does work.

Thanks @david.wylie. I’ll have a proper look at this tomorrow. From a quick glance I think it’s exactly what I need to progress!

I’ll let you know what I end up with!

1 Like

on the ComponentForm show event I have:

anvil.js.call_js('set_enter_behaviour') 

I think you might want to use self.call_js(...) here rather than anvil.js.call_js(...). Some background:

There are two ways to call JS from Python in Anvil: locally (on a component) and globally (not on a particular component):

  • Locally, you can call self.call_js(...) from any HTML-templated form. You will call the Javascript with this set to the DOM element from the form you’re calling in.

    This is really useful if you’re creating a custom component and you expect to have multiple instances on the page – you can tell the Javascript to do something to this instance.

  • Globally, you can call anvil.js.call_js(...) from anywhere. There’s no local context here - you’re not calling the Javascript on a particular DOM element.

    This is really useful if you want to do something that’s not specific to a particular part of the page (eg calling a JS library to pop up a dialog box).


It looks like, for what you’re doing, you want to operate on on a particular instance of your custom component, so I would recommend using self.call_js() in the custom component, and using this in Javascript to work out which DOM element(s) to operate on.

@stucork -

what @meredydd wrote here :

is essentially what my example app does, though probably not quite as neatly as if @meredydd had written it :slight_smile:

1 Like

I see - yes so the conclusion - whenever you want to augment the behaviour of an anvil component…
Turn this into a custom HTML component and use self.call_js to augment that behaviour.
This allows one to have multiple instances of that component.

This is what I’ve done with it…
Thanks @meredydd and @david.wylie for the help!
https://anvil.works/build#clone:2AYDI2MD5L2KAKFM=NKJKLV73UCNUZ2CINT3XP6UA

2 Likes